Eu tenho uma função que eu quero tomar, como parâmetro, uma matriz 2D de tamanho variável.
Até agora eu tenho o seguinte:
void myFunction(double** myArray){
myArray[x][y] = 5;
etc...
}
E eu declarei uma matriz em outro lugar no meu código:
double anArray[10][10];
No entanto, chamar myFunction(anArray)
me dá um erro.
Não quero copiar a matriz quando a transmitir. Todas as alterações feitas myFunction
devem alterar o estado de anArray
. Se entendi corretamente, só quero passar como argumento um ponteiro para uma matriz 2D. A função também precisa aceitar matrizes de tamanhos diferentes. Então, por exemplo, [10][10]
e [5][5]
. Como posso fazer isso?
c++
arrays
pointers
multidimensional-array
RogerDarwin
fonte
fonte
func(int* mat, int r, int c){ for(int i=0; i<r; i++) for(int j=0; j<c; j++) printf("%d ", *(mat+i*c+j)); }
. Chame-o como-int mat[3][5]; func(mat[0], 3, 5);
Respostas:
Existem três maneiras de passar uma matriz 2D para uma função:
O parâmetro é uma matriz 2D
O parâmetro é uma matriz que contém ponteiros
O parâmetro é um ponteiro para um ponteiro
fonte
array
comarray[i][j]
:)int (*a)[10]
.int **
.int (*a) [10]
.Tamanho fixo
1. Passe por referência
No C ++, passar a matriz por referência sem perder as informações da dimensão é provavelmente o mais seguro, pois não é necessário se preocupar com o chamador passando uma dimensão incorreta (sinalizadores do compilador quando não correspondem). No entanto, isso não é possível com matrizes dinâmicas (armazenamento livre); ele funciona apenas para matrizes automáticas ( geralmente com vida útil da pilha ), ou seja, a dimensionalidade deve ser conhecida no momento da compilação.
2. Passe pelo ponteiro
O equivalente em C do método anterior está passando a matriz por ponteiro. Isso não deve ser confundido com a passagem pelo tipo de ponteiro deteriorado da matriz (3) , que é o método comum e popular, embora menos seguro que esse, mas mais flexível. Como (1) , use esse método quando todas as dimensões da matriz forem fixas e conhecidas em tempo de compilação. Observe que, ao chamar a função, o endereço da matriz deve ser passado
process_2d_array_pointer(&a)
e não o endereço do primeiro elemento por deterioraçãoprocess_2d_array_pointer(a)
.Tamanho variável
Eles são herdados de C, mas são menos seguros, o compilador não tem como verificar, garantindo que o chamador esteja passando as dimensões necessárias. A função baseia-se apenas no que o chamador passa como as dimensões. Elas são mais flexíveis do que as anteriores, já que matrizes de diferentes comprimentos podem ser passadas para elas invariavelmente.
Deve-se lembrar que não existe uma passagem direta de uma matriz para uma função em C [enquanto em C ++ elas podem ser passadas como referência (1) ]; (2) está passando um ponteiro para a matriz e não a própria matriz. Sempre passar uma matriz como está se torna uma operação de cópia de ponteiro, facilitada pela natureza da matriz de decair em um ponteiro .
3. Passe por (valor) um ponteiro para o tipo deteriorado
Embora
int array[][10]
seja permitido, eu não recomendaria a sintaxe acima, pois a sintaxe acima deixa claro que o identificadorarray
é um ponteiro único para uma matriz de 10 números inteiros, enquanto essa sintaxe parece uma matriz 2D, mas é o mesmo ponteiro para uma matriz de 10 números inteiros. Aqui sabemos o número de elementos em uma única linha (ou seja, o tamanho da coluna, 10 aqui), mas o número de linhas é desconhecido e, portanto, deve ser passado como argumento. Nesse caso, há alguma segurança, pois o compilador pode sinalizar quando um ponteiro para uma matriz com segunda dimensão diferente de 10 é passado. A primeira dimensão é a parte variável e pode ser omitida. Veja aqui a justificativa de por que somente a primeira dimensão pode ser omitida.4. Passe o ponteiro para um ponteiro
Novamente, há uma sintaxe alternativa
int *array[10]
da mesmaint **array
. Nesta sintaxe, o[10]
é ignorado quando se decompõe em um ponteiro, tornando-se assimint **array
. Talvez seja apenas uma sugestão para o chamador que a matriz passada tenha pelo menos 10 colunas; mesmo assim, a contagem de linhas é necessária. De qualquer forma, o compilador não sinaliza violações de tamanho / tamanho (apenas verifica se o tipo passado é um ponteiro para o ponteiro), exigindo, portanto, a contagem de linhas e colunas, pois o parâmetro faz sentido aqui.Nota: (4) é a opção menos segura, pois quase não possui verificação de tipo e é a mais inconveniente. Não se pode legitimamente passar uma matriz 2D para essa função; O C-FAQ condena a solução usual de fazer
int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);
, pois pode levar a um comportamento indefinido devido ao achatamento da matriz. A maneira correta de passar uma matriz nesse método nos leva à parte inconveniente, ou seja, precisamos de uma matriz adicional (substituta) de ponteiros, com cada um de seus elementos apontando para a respectiva linha da matriz real a ser passada; esse substituto é então passado para a função (veja abaixo); tudo isso para realizar o mesmo trabalho que os métodos acima, mais seguros, limpos e talvez mais rápidos.Aqui está um programa de driver para testar as funções acima:
fonte
b[i] = a[i];
para, digamosb[i] = new int[10];
,. Pode-se também fazerb
alocados dinamicamenteint **b = int *[5];
e ainda funcionará como está.array[i][j]
funciona na função em 4) ? Porque ele recebeu ptr para ptr e não sabe o valor da última dimensão, o que é necessário para executar uma mudança para o endereçamento correto?array[i][j]
é apenas aritmética do ponteiro, ou seja, para o valor do ponteiroarray
, ele adicionai
e desreferencia o resultado comoint*
, ao qual ele adicionaj
e desreferencia esse local, lendo umint
. Portanto, não, ele não precisa conhecer nenhuma dimensão para isso. Mas, esse é o ponto! O compilador leva a palavra do programador em fé e, se o programador estiver incorreto, o comportamento indefinido se seguirá. Essa é a razão pela qual eu mencionei que o caso 4 é a opção menos segura.Uma modificação na primeira sugestão do shengy, você pode usar modelos para fazer a função aceitar uma variável de matriz multidimensional (em vez de armazenar uma matriz de ponteiros que precisam ser gerenciados e excluídos):
As instruções print estão lá para mostrar que as matrizes estão sendo passadas por referência (exibindo os endereços das variáveis)
fonte
%p
para imprimir um ponteiro e, mesmo assim, deve convertê-lovoid *
, caso contrário,printf()
invoca um comportamento indefinido. Além disso, você não deve usar o&
operador addressof ( ) ao chamar as funções, pois as funções esperam um argumento do tipodouble (*)[size_y]
, enquanto você as passadouble (*)[10][10]
edouble (*)[5][5]
.Surpreendeu-se que ninguém tenha mencionado isso ainda, mas você pode simplesmente usar o modelo em qualquer coisa que suporte 2D [] [] semântica.
Ele funciona com qualquer estrutura de dados 2D "tipo matriz", como
std::vector<std::vector<T>>
um tipo definido pelo usuário, para maximizar a reutilização de código.fonte
Você pode criar um modelo de função como este:
Então você tem os dois tamanhos de dimensão via R e C. Uma função diferente será criada para cada tamanho de matriz, portanto, se sua função for grande e você a chamar com uma variedade de tamanhos de matriz diferentes, isso poderá ser caro. Você pode usá-lo como um invólucro sobre uma função como esta:
Ele trata o array como unidimensional e usa aritmética para descobrir as compensações dos índices. Nesse caso, você definiria o modelo assim:
fonte
size_t
é o melhor tipo para índices de matriz do queint
.anArray[10][10]
não é um ponteiro para um ponteiro, é um pedaço de memória contíguo adequado para armazenar 100 valores do tipo double, que o compilador sabe endereçar porque você especificou as dimensões. Você precisa passá-lo para uma função como uma matriz. Você pode omitir o tamanho da dimensão inicial, da seguinte maneira:No entanto, isso não permitirá que você passe matrizes com a última dimensão diferente de dez.
A melhor solução em C ++ é usar
std::vector<std::vector<double> >
: é quase tão eficiente e significativamente mais conveniente.fonte
A matriz unidimensional decai para um ponteiro apontando para o primeiro elemento na matriz. Enquanto uma matriz 2D se deteriora para um ponteiro apontando para a primeira linha. Portanto, o protótipo de função deve ser -
Eu preferiria
std::vector
matrizes brutas.fonte
Você pode fazer algo assim ...
Sua saída será a seguinte ...
fonte
Aqui está um vetor de exemplo de matriz de vetores
resultado:
fonte
Podemos usar várias maneiras de passar um array 2D para uma função:
Usando o ponteiro único , temos que converter a matriz em 2D.
Usando o ponteiro duplo Dessa maneira, também criamos a matriz 2D
fonte
Uma coisa importante para a passagem de matrizes multidimensionais é:
First array dimension
não precisa ser especificado.Second(any any further)dimension
deve ser especificado.1.Quando apenas a segunda dimensão estiver disponível globalmente (como macro ou como constante global)
2.Utilizando um ponteiro único : Neste método, precisamos converter a matriz 2D ao passar para a função.
fonte
Você pode usar o recurso de modelo em C ++ para fazer isso. Eu fiz algo parecido com isto:
o problema com essa abordagem é que, para cada valor de col que você fornece, a nova definição de função é instanciada usando o modelo. tão,
instancia o modelo duas vezes para produzir 2 definições de função (uma em que col = 3 e outra em que col = 5).
fonte
Se você deseja passar
int a[2][3]
paravoid func(int** pp)
você, precisa das etapas auxiliares a seguir.Como o primeiro
[2]
pode ser especificado implicitamente, pode ser ainda mais simplificado como.fonte
No caso de você desejar passar uma matriz 2D de tamanho dinâmico para uma função, o uso de alguns ponteiros pode funcionar para você.
fonte
Você tem permissão para omitir a dimensão mais à esquerda e, portanto, acaba com duas opções:
O mesmo acontece com os ponteiros:
A deterioração de uma matriz dimensional N para um ponteiro para a matriz dimensional N-1 é permitida pelo padrão C ++ , pois você pode perder a dimensão mais à esquerda e ainda conseguir acessar corretamente os elementos da matriz com informações de dimensão N-1.
Detalhes aqui
Porém, matrizes e ponteiros não são os mesmos : uma matriz pode se decompor em um ponteiro, mas um ponteiro não transmite estado sobre o tamanho / configuração dos dados para os quais aponta.
A
char **
é um ponteiro para um bloco de memória contendo ponteiros de caracteres , os quais apontam para blocos de caracteres de memória. Achar [][]
é um único bloco de memória que contém caracteres. Isso afeta a forma como o compilador traduz o código e como será o desempenho final.Fonte
fonte