Como declaro uma matriz 2D usando new?
Como, para uma matriz "normal", eu faria:
int* ary = new int[Size]
mas
int** ary = new int[sizeY][sizeX]
a) não funciona / compila eb) não realiza o que:
int ary[sizeY][sizeX]
faz.
c++
arrays
multidimensional-array
dynamic-allocation
user20844
fonte
fonte
Respostas:
Uma matriz 2D dinâmica é basicamente uma matriz de ponteiros para matrizes . Você pode inicializá-lo usando um loop, assim:
O acima, para
colCount= 5
erowCount = 4
, produziria o seguinte:fonte
new
é criada no heap e deve ser desalocadadelete
, apenas lembre-se disso e exclua essa memória da pilha quando terminar para evitar vazamentos.T (*ptr)[M] = new T[N][M];
é a solução correta ... Nenhuma quantidade de matrizes de-ponteiros nunca vai ser o mesmo como uma matriz-de-matrizes ...deveria estar:
e a limpeza seria:
EDIT: como Dietrich Epp apontou nos comentários, esta não é exatamente uma solução leve. Uma abordagem alternativa seria usar um grande bloco de memória:
fonte
i*sizeX+j
? Se bem me lembro, com a ordenação de linhas principais, deve ser row * numColumns + col.Embora essa resposta popular ofereça a sintaxe de indexação desejada, ela é duplamente ineficiente: grande e lenta no espaço e no tempo. Existe uma maneira melhor.
Por que essa resposta é grande e lenta
A solução proposta é criar uma matriz dinâmica de ponteiros, inicializando cada ponteiro em sua própria matriz dinâmica independente. A vantagem dessa abordagem é que ela fornece a sintaxe de indexação à qual você está acostumado. Portanto, se você deseja encontrar o valor da matriz na posição x, y, você diz:
Isso funciona porque a matriz [x] retorna um ponteiro para uma matriz, que é indexada com [y]. Dividindo:
Conveniente, sim? Nós gostamos da nossa sintaxe [x] [y].
Mas a solução tem uma grande desvantagem , que é gorda e lenta.
Por quê?
A razão pela qual é gorda e lenta é realmente a mesma. Cada "linha" na matriz é uma matriz dinâmica alocada separadamente. Fazer uma alocação de heap é caro, tanto no tempo quanto no espaço. O alocador leva tempo para fazer a alocação, às vezes executando algoritmos O (n) para fazer isso. E o alocador "preenche" cada uma de suas matrizes de linha com bytes extras para contabilidade e alinhamento. Esse espaço extra custa ... bem ... espaço extra. O desalocador também levará um tempo extra quando você desalocar a matriz, liberando minuciosamente cada alocação de linha individual. Me deixa suado só de pensar nisso.
Há outra razão pela qual é lento. Essas alocações separadas tendem a viver em partes descontínuas da memória. Uma linha pode estar no endereço 1.000, outra no endereço 100.000 - você entendeu. Isso significa que, quando você está atravessando a matriz, está pulando na memória como uma pessoa selvagem. Isso tende a resultar em falhas de cache que diminuem bastante o tempo de processamento.
Portanto, se você absolutamente deve ter sua sintaxe de indexação [x] [y], use essa solução. Se você deseja rapidez e pequenez (e se não se importa com isso, por que está trabalhando em C ++?), Precisa de uma solução diferente.
Uma solução diferente
A melhor solução é alocar toda a sua matriz como uma única matriz dinâmica e, em seguida, use sua (ligeiramente) matemática de indexação inteligente para acessar as células. A matemática da indexação é apenas um pouco inteligente; nah, não é nada inteligente: é óbvio.
Dada esta
index()
função (que eu imagino ser membro de uma classe porque precisa conhecer am_width
matriz), você pode acessar células dentro de sua matriz. A matriz matriz é alocada assim:Portanto, o equivalente a isso na solução lenta e gorda:
... é isso na solução pequena e rápida:
Triste, eu sei. Mas você vai se acostumar. E sua CPU agradecerá.
fonte
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; } };
Se você endireitar esse código, pode fazer sentido e esclarecer a resposta acima.#define ROW_COL_TO_INDEX(row, col, num_cols) (row*num_cols + col)
Você pode usá-lo comoint COLS = 4; A[ ROW_COL_TO_INDEX(r, c, COLS) ] = 75;
A sobrecarga realmente afeta quando fazemos multiplicações de matrizes que são de complexidade O (n ^ 3) ou O (n ^ 2,81) para o algoritmo de Strassen .a[x][y]
, o que você está realmente fazendo é*(*(a + x) + y)
: duas adições e duas buscas na memória. Coma[index(x, y)]
, o que você está realmente fazendo é*(a + x + w*y)
: duas adições, uma multiplicação e uma busca de memória. O último é geralmente preferível, pelas razões expostas nesta resposta (ou seja, negociar a busca de memória extra com uma multiplicação vale a pena, especialmente porque os dados não são fragmentados e, portanto, você não perde o cache).No C ++ 11 é possível:
Dessa forma, a memória não é inicializada. Para inicializar, faça o seguinte:
Programa de exemplo (compile com "g ++ -std = c ++ 11"):
Resultado:
fonte
using arr2d = double(*)[2]; arr2d array = new double[M][N];
double (*)[M][N]
oudouble(*)[][N]
N, sendo expressões constantes.Presumo que, a partir do seu exemplo de matriz estática, você deseja uma matriz retangular, e não irregular. Você pode usar o seguinte:
Então você pode acessar elementos como:
Não esqueça de usar delete []
ary
.fonte
Existem duas técnicas gerais que eu recomendaria para isso no C ++ 11 e superior, uma para dimensões de tempo de compilação e outra para tempo de execução. Ambas as respostas assumem que você deseja matrizes uniformes e bidimensionais (e não irregulares).
Dimensões do tempo de compilação
Use um
std::array
destd::array
e, em seguida, use-onew
para colocá-lo na pilha:Novamente, isso só funciona se os tamanhos das dimensões forem conhecidos em tempo de compilação.
Dimensões do tempo de execução
A melhor maneira de realizar uma matriz bidimensional com tamanhos conhecidos apenas em tempo de execução é agrupá-la em uma classe. A classe alocará uma matriz 1d e sobrecarregará
operator []
para fornecer indexação para a primeira dimensão. Isso funciona porque, em C ++, uma matriz 2D é de linha principal:(Retirado de http://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays/ )
Uma sequência contígua de memória é boa por razões de desempenho e também é fácil de limpar. Aqui está um exemplo de classe que omite muitos métodos úteis, mas mostra a ideia básica:
Então, criamos uma matriz com
std::make_unique<int[]>(rows * columns)
entradas. Sobrecarregamos ooperator []
que indexará a linha para nós. Retorna umint *
que aponta para o início da linha, que pode ser desreferenciado como normal para a coluna. Observe que omake_unique
primeiro é enviado no C ++ 14, mas você pode preenchê-lo no C ++ 11, se necessário.Também é comum que esses tipos de estruturas sobrecarreguem
operator()
também:Tecnicamente, não usei
new
aqui, mas é trivial passar destd::unique_ptr<int[]>
paraint *
e usarnew
/delete
.fonte
std::array
destd::array
s:std::array<std::array<int, columns> rows>
.asserts
para compilações de depuração para verificar acessos à memória, etc. Essas adições geralmente tornam mais fácil e agradável trabalhar.make_unique
vez denew/delete
.Essa pergunta estava me incomodando - é um problema bastante comum que uma boa solução já deveria existir, algo melhor que o vetor de vetores ou rolando sua própria indexação de matriz.
Quando algo deveria existir em C ++, mas não existe, o primeiro lugar para procurar é boost.org . Lá encontrei a Boost Multidimensional Array Library
multi_array
,. Inclusive inclui umamulti_array_ref
classe que pode ser usada para quebrar seu próprio buffer de matriz unidimensional.fonte
auto
palavra - chave. Estou surpreso que eles não tenham tentado lidar com matrizes 2D, especialmente porque o Boost já mostrou o caminho.Por que não usar STL: vector? Tão fácil e você não precisa excluir o vetor.
Você também pode inicializar as 'matrizes', apenas dê um valor padrão
Fonte: Como criar matrizes dimensionais 2, 3 (ou multi) em C / C ++?
fonte
Uma matriz 2D é basicamente uma matriz 1D de ponteiros, onde cada ponteiro está apontando para uma matriz 1D, que retém os dados reais.
Aqui N é linha e M é coluna.
alocação dinâmica
preencher
impressão
livre
fonte
Como alocar uma matriz multidimensional contígua no GNU C ++? Há uma extensão GNU que permite que a sintaxe "padrão" funcione.
Parece que o problema vem do operador new []. Certifique-se de usar o operador new:
E é tudo: você obtém uma matriz multidimensional compatível com C ...
fonte
double (*in)[m][n] = (double (*)[m][n])new double[k*m*n];
também não funciona. Estou recebendo erros C2057, C2540n
porque não é conhecido no momento da compilação. Não entendo por que não posso fazê-lo, porque a memória é alocada corretamente e são apenas indicadores para lidar com essa memória convenientemente. (VS 2010)gcc
me enganou quando escrevi o seguinte: o fornecimento-std=c++11
não é suficiente para ativar a conformidade padrão estrita, também-pedantic-errors
é necessário. Sem a bandeira posterior, elegcc
aceita o elenco com satisfação, mesmo que não esteja de acordo com o padrão C ++. Com o que sei agora, só posso aconselhar voltar a C ao fazer coisas que dependem fortemente de matrizes multidimensionais. O C99 é apenas muito mais poderoso nesse aspecto do que o C ++ 17 será.typedef é seu amigo
Depois de voltar e examinar muitas das outras respostas, descobri que há uma explicação mais profunda, pois muitas das outras respostas sofrem de problemas de desempenho ou forçam você a usar uma sintaxe incomum ou onerosa para declarar a matriz ou acessar a matriz elementos (ou todos os itens acima).
Primeiro, esta resposta assume que você conhece as dimensões da matriz em tempo de compilação. Se o fizer, esta é a melhor solução, pois fornecerá o melhor desempenho e permitirá que você use a sintaxe padrão da matriz para acessar os elementos da matriz .
A razão pela qual isso oferece o melhor desempenho é porque aloca todas as matrizes como um bloco de memória contíguo, o que significa que você provavelmente terá menos falhas de página e melhor localidade espacial. A alocação em um loop pode fazer com que as matrizes individuais acabem espalhadas em várias páginas não contíguas pelo espaço de memória virtual, pois o loop de alocação pode ser interrompido (possivelmente várias vezes) por outros threads ou processos, ou simplesmente devido à discrição do alocador preenchendo pequenos blocos de memória vazios disponíveis.
Os outros benefícios são uma sintaxe de declaração simples e uma sintaxe de acesso à matriz padrão.
Em C ++ usando new:
Ou estilo C usando calloc:
fonte
Esse problema me incomoda há 15 anos e todas as soluções fornecidas não foram satisfatórias para mim. Como você cria uma matriz multidimensional dinâmica contiguamente na memória? Hoje finalmente encontrei a resposta. Usando o código a seguir, você pode fazer exatamente isso:
Quando você invoca o programa com os valores sizeX = 20 e sizeY = 15, a saída será a seguinte:
Como você pode ver, a matriz multidimensional está contígua na memória e não há dois endereços de memória sobrepostos. Mesmo a rotina para liberar a matriz é mais simples que a maneira padrão de alocar dinamicamente a memória para cada coluna (ou linha, dependendo de como você visualiza a matriz). Como a matriz consiste basicamente em duas matrizes lineares, somente essas duas precisam ser (e podem ser) liberadas.
Este método pode ser estendido para mais de duas dimensões com o mesmo conceito. Não vou fazer isso aqui, mas quando você entende a ideia, é uma tarefa simples.
Espero que este código o ajude tanto quanto me ajudou.
fonte
array2d[i] = buffer + i * sizeX
. Portanto, isso ajuda um pouco, mas no código usando a matriz, o compilador não pode apenas incrementar ponteiros para varrer a matriz.make_unique<int[]>(sizeX*sizeY)
para configurar o armazenamento contíguo emake_unique<int*[]>(sizeX)
configurar o armazenamento para os ponteiros (que devem ser atribuídos da mesma maneira que você mostra). Isso libera você do requisito de ligardelete[]
duas vezes no final.temp
? Considerando os benefícios (array 2d contínuo com dimensões desconhecidas em tempo de compilação), não tenho certeza se me importo de tê-lo pendurado. Eu não entendi o que @ PeterCordes quer dizer comextra layer of indirection
, o que é? Por que o parêntesearray2d[i] = (temp + i * sizeX)
;O objetivo desta resposta não é adicionar nada novo que os outros ainda não abordem, mas estender a resposta de @Kevin Loney.
Você pode usar a declaração leve:
e sintaxe de acesso será:
mas isso é complicado para a maioria e pode causar confusão. Portanto, você pode definir uma macro da seguinte maneira:
Agora você pode acessar a matriz usando a sintaxe muito semelhante
ary(i, j) // means ary[i][j]
. Isso tem as vantagens de ser simples e bonito e, ao mesmo tempo, usar expressões no lugar dos índices também é mais simples e menos confuso.Para acessar, digamos, ary [2 + 5] [3 + 8], você pode escrever em
ary(2+5, 3+8)
vez da aparência complexa,ary[(2+5)*SizeY + (3+8)]
ou seja, salva parênteses e ajuda na legibilidade.Ressalvas:
SizeY
ele deve ser passado com o mesmo nome (ou, em vez disso, ser declarado como uma variável global).Ou, se você precisar usar a matriz em várias funções, poderá adicionar SizeY também como outro parâmetro na definição de macro da seguinte forma:
Você entendeu a ideia. Obviamente, isso se torna muito longo para ser útil, mas ainda pode impedir a confusão de + e *.
Definitivamente, isso não é recomendado e será condenado como má prática pela maioria dos usuários experientes, mas não pude resistir a compartilhá-lo devido à sua elegância.
Edit:
Se você deseja uma solução portátil que funcione para qualquer número de matrizes, você pode usar esta sintaxe:
e, em seguida, você pode transmitir qualquer matriz para a chamada, com qualquer tamanho, usando a sintaxe de acesso:
PS: Eu testei isso, e a mesma sintaxe funciona (como lvalue e rvalue) nos compiladores g ++ 14 e g ++ 11.
fonte
Tente fazer isso:
fonte
Aqui, eu tenho duas opções. O primeiro mostra o conceito de uma matriz de matrizes ou ponteiro de ponteiros. Prefiro o segundo porque os endereços são contíguos, como você pode ver na imagem.
fonte
Se seu projeto for CLI (Common Language Runtime Support) , então:
Você pode usar a classe array, não aquela que você obtém ao escrever:
Em outras palavras, não a classe de matriz não gerenciada que você obtém ao usar o espaço para nome std e ao incluir o cabeçalho da matriz, não a classe de matriz não gerenciada definida no espaço de nome std e no cabeçalho da matriz, mas a matriz de classe gerenciada da CLI.
com essa classe, você pode criar uma matriz de qualquer classificação que desejar.
O código a seguir abaixo cria uma nova matriz bidimensional de 2 linhas e 3 colunas e do tipo int, e o nomeio "arr":
Agora você pode acessar os elementos da matriz, nomeie-os e escreva apenas um parênteses ao quadrado
[]
e, dentro deles, adicione a linha e a coluna e separe-os com a vírgula,
.O código a seguir abaixo acessa um elemento na 2ª linha e na 1ª coluna da matriz que eu já criei no código anterior acima:
escrever apenas esta linha é ler o valor nessa célula, ou seja, obter o valor nessa célula, mas se você adicionar o
=
sinal de igual , está prestes a escrever o valor nessa célula, ou seja, definir o valor nessa célula. Você também pode usar os operadores + =, - =, * = e / =, é claro, apenas para números (int, float, double, __int16, __int32, __int64 e etc), mas com certeza já o conhece.Se o seu projeto não for CLI, você poderá usar a classe de matriz não gerenciada do espaço de nome std, se é
#include <array>
claro, mas o problema é que essa classe de matriz é diferente da matriz da CLI. Criar matriz desse tipo é igual à CLI, exceto que você precisará remover o^
sinal e agcnew
palavra - chave. Mas, infelizmente, o segundo parâmetro int entre<>
parênteses especifica o comprimento (ou seja, tamanho) da matriz, não sua classificação!Não há como especificar classificação neste tipo de matriz, a classificação é apenas o recurso da matriz CLI . .
matriz std se comporta como matriz normal em c ++, que você define com ponteiro, por exemplo
int*
e depoisnew int[size]
:, ou sem ponteiro:,int arr[size]
mas diferente da matriz normal do c ++, a matriz std fornece funções que você pode usar com os elementos da matriz, como preenchimento, início, fim, tamanho e etc., mas a matriz normal não fornece nada .Mas ainda o array std é um array dimensional, como os arrays c ++ normais. Mas, graças às soluções sugeridas pelos outros funcionários sobre como você pode criar o array unidimensional c ++ normal para o array bidimensional, podemos adaptar as mesmas idéias ao array std, por exemplo, de acordo com a idéia de Mehrdad Afshari, podemos escrever o seguinte código:
Essa linha de código cria uma "matriz jugged" , que é uma matriz unidimensional em que cada uma de suas células é ou aponta para outra matriz unidimensional.
Se todas as matrizes unidimensionais em uma matriz dimensional são iguais em seu comprimento / tamanho, você pode tratar a variável array2d como uma matriz bidimensional real, além de usar métodos especiais para tratar linhas ou colunas, depende de como você a visualiza. em mente, na matriz 2D, essa matriz padrão suporta.
Você também pode usar a solução de Kevin Loney:
mas se você usar a matriz std, o código deverá ser diferente:
E ainda tem as funções exclusivas da matriz std.
Observe que você ainda pode acessar os elementos da matriz std usando os
[]
parênteses e não precisa chamar aat
função. Você também pode definir e atribuir uma nova variável int que irá calcular e manter o número total de elementos na matriz std e usar seu valor, em vez de repetirsizeX*sizeY
Você pode definir sua própria classe genérica de matriz bidimensional e definir o construtor da classe de matriz bidimensional para receber dois números inteiros para especificar o número de linhas e colunas na nova matriz bidimensional e definir a função get que recebe dois parâmetros de número inteiro que acessam um elemento na matriz bidimensional e retornam seu valor e definem a função que recebe três parâmetros, que os dois primeiros são números inteiros que especificam a linha e a coluna na matriz bidimensional e o terceiro parâmetro é o novo valor do elemento. Seu tipo depende do tipo que você escolheu na classe genérica.
Você será capaz de implementar tudo isso usando tanto o c normais ++ matriz (ponteiros ou sem) ou a matriz de DST e uso uma das ideias que outras pessoas sugeridas, e torná-lo fácil de usar como a matriz cli, ou como os dois matriz dimensional que você pode definir, atribuir e usar em C #.
fonte
Comece definindo a matriz usando ponteiros (Linha 1):
fonte
O exemplo abaixo pode ajudar,
fonte
Se você deseja uma matriz 2D de números inteiros, cujos elementos são alocados seqüencialmente na memória, declare-a como
onde, em vez de x, você pode escrever qualquer dimensão, mas n deve ser o mesmo em dois lugares. Exemplo
deve imprimir 6.
fonte
Eu deixei você com uma solução que funciona melhor para mim, em certos casos. Especialmente se alguém souber [o tamanho de?] Uma dimensão da matriz. Muito útil para uma matriz de caracteres, por exemplo, se precisarmos de uma matriz de tamanho variável de matrizes de caracteres [20].
A chave são os parênteses na declaração da matriz.
fonte
Usei este sistema não elegante, mas RÁPIDO, FÁCIL e TRABALHADOR. Não vejo por que não pode funcionar porque a única maneira do sistema permitir criar uma matriz de tamanho grande e acessar peças é sem cortá-la em partes:
fonte
Não sei ao certo se a resposta a seguir não foi fornecida, mas decidi adicionar algumas otimizações locais à alocação da matriz 2D (por exemplo, uma matriz quadrada é feita através de apenas uma alocação):
int** mat = new int*[n]; mat[0] = new int [n * n];
No entanto, a exclusão é assim devido à linearidade da alocação acima:
delete [] mat[0]; delete [] mat;
fonte
declarando matriz 2D dinamicamente:
Agora, no código acima, pegamos um ponteiro duplo e atribuímos a ele uma memória dinâmica e fornecemos um valor para as colunas. Aqui a memória alocada é apenas para as colunas, agora para as linhas, precisamos apenas de um loop for e atribuímos ao valor de cada memória dinâmica uma linha. Agora podemos usar o ponteiro da mesma maneira que usamos uma matriz 2D. No exemplo acima, atribuímos números aleatórios à nossa matriz 2D (ponteiro). Tudo sobre DMA da matriz 2D.
fonte
Estou usando isso ao criar matriz dinâmica. Se você tem uma classe ou uma estrutura. E isso funciona. Exemplo:
fonte