Preciso de um ponteiro para uma matriz bidimensional estática. Como isso é feito?
static uint8_t l_matrix[10][20];
void test(){
uint8_t **matrix_ptr = l_matrix; //wrong idea
}
Recebo todos os tipos de erros como:
- aviso: atribuição de tipo de ponteiro incompatível
- o valor subscrito não é array nem ponteiro
- erro: uso inválido de membro de matriz flexível
Respostas:
Aqui você quer fazer um ponteiro para o primeiro elemento da matriz
Com typedef, isso parece mais limpo
Então você pode aproveitar a vida novamente :)
Cuidado com o mundo de ponteiro / array em C, pois há muita confusão em torno disso.
Editar
Revendo algumas das outras respostas aqui, porque os campos de comentário são muito curtos para fazer lá. Múltiplas alternativas foram propostas, mas não foi demonstrado como elas se comportam. É assim que eles fazem
Se você corrigir o erro e adicionar o operador de endereço
&
como no seguinte trechoEntão aquele cria um ponteiro para um tipo de array incompleto de elementos do tipo array de 20 uint8_t. Como o ponteiro é para uma matriz de matrizes, você deve acessá-lo com
E porque é um ponteiro para uma matriz incompleta, você não pode fazer como um atalho
Porque a indexação requer que o tamanho do tipo de elemento seja conhecido (indexar implica na adição de um inteiro ao ponteiro, então não funcionará com tipos incompletos). Observe que isso só funciona em
C
, porqueT[]
eT[N]
são tipos compatíveis. C ++ não tem um conceito de tipos compatíveis e, portanto, rejeitará esse código, poisT[]
eT[10]
são tipos diferentes.A alternativa a seguir não funciona, porque o tipo de elemento da matriz, quando você a visualiza como uma matriz unidimensional, não é
uint8_t
, masuint8_t[20]
O seguinte é uma boa alternativa
Você acessa com
Tem a vantagem de preservar o tamanho da dimensão externa. Então você pode aplicar sizeof nele
Há uma outra resposta que faz uso do fato de que os itens em uma matriz são armazenados de forma contígua
Agora, isso formalmente só permite acessar os elementos do primeiro elemento do array bidimensional. Ou seja, a seguinte condição é mantida
Você notará que provavelmente funciona até
10*20-1
, mas se você lançar na análise de alias e outras otimizações agressivas, algum compilador pode fazer uma suposição que pode quebrar esse código. Dito isso, eu nunca encontrei um compilador que falhe nele (mas, novamente, eu não usei essa técnica em código real), e até mesmo o C FAQ contém essa técnica (com um aviso sobre seu UB'ness ), e se você não pode alterar o tipo de array, esta é a última opção para salvá-lo :)fonte
uint8_t *d[20]
, que cria um array de 3 ponteiros para uint8_t, mas isso não funcionaria neste caso.Para entender isso totalmente , você deve compreender os seguintes conceitos:
Arrays não são ponteiros!
Em primeiro lugar (e tem sido pregado o suficiente), matrizes não são ponteiros . Em vez disso, na maioria dos usos, eles 'decaem' para o endereço de seu primeiro elemento, que pode ser atribuído a um ponteiro:
Presumo que funcione dessa forma para que o conteúdo do array possa ser acessado sem copiar todos eles. Isso é apenas um comportamento de tipos de array e não significa que eles sejam a mesma coisa.
Matrizes multidimensionais
Arrays multidimensionais são apenas uma forma de 'particionar' a memória de uma forma que o compilador / máquina possa entender e operar.
Por exemplo,
int a[4][3][5]
= uma matriz contendo 4 * 3 * 5 (60) 'pedaços' de memória de tamanho inteiro.A vantagem sobre o uso do
int a[4][3][5]
vs plainint b[60]
é que agora eles estão 'particionados' (mais fácil de trabalhar com seus 'pedaços', se necessário), e o programa agora pode realizar a verificação vinculada.Na verdade,
int a[4][3][5]
é armazenado exatamente comoint b[60]
na memória - A única diferença é que o programa agora o gerencia como se fossem entidades separadas de certos tamanhos (especificamente, quatro grupos de três grupos de cinco).Lembre-se:
int a[4][3][5]
eint b[60]
são iguais na memória, e a única diferença é como são tratados pelo aplicativo / compiladorA partir disso, você pode ver claramente que cada "partição" é apenas um array que o programa controla.
Sintaxe
Agora, os arrays são sintaticamente diferentes dos ponteiros . Especificamente, isso significa que o compilador / máquina os tratará de maneira diferente. Isso pode parecer óbvio, mas dê uma olhada nisto:
O exemplo acima imprime o mesmo endereço de memória duas vezes, assim:
No entanto, apenas um pode ser atribuído a um ponteiro de forma tão direta :
Por que não pode
a
ser atribuído a um ponteiro, masa[0]
pode?Isso, simplesmente, é uma consequência de matrizes multidimensionais, e vou explicar por quê:
No nível de '
a
', ainda vemos que temos outra 'dimensão' pela qual esperar. No nível de 'a[0]
', entretanto, já estamos na dimensão superior, portanto, no que diz respeito ao programa, estamos apenas olhando para um array normal.Você pode estar perguntando:
Por que é importante se o array é multidimensional em relação a fazer um ponteiro para ele?
É melhor pensar assim:
Um 'decaimento' de um array multidimensional não é apenas um endereço, mas um endereço com dados de partição (também conhecido como ele ainda entende que seus dados subjacentes são feitos de outros arrays), que consiste em limites definidos pelo array além da primeira dimensão.
Esta lógica de 'partição' não pode existir dentro de um ponteiro, a menos que o especifiquemos:
Caso contrário, o significado das propriedades de classificação da matriz será perdido.
Observe também o uso de parênteses em torno de
*p
:int (*p)[5][95][8]
- Isso é para especificar que estamos fazendo um ponteiro com esses limites, não uma matriz de ponteiros com esses limites:int *p[5][95][8]
Conclusão
Vamos revisar:
Em resumo: arrays multidimensionais decaem para endereços que carregam a capacidade de entender seus conteúdos.
fonte
int *p1 = &(a[0]); // RIGHT !
Na verdade, é idêntico aint *p1 = a;
No
você pode acessar como
afinal, as matrizes bidimensionais também são armazenadas como 1-d.
fonte
Bom dia,
A declaração
reservou armazenamento para 10 linhas de 20 locais unit8_t, ou seja, 200 locais de tamanho uint8_t, com cada elemento sendo encontrado calculando 20 x linha + coluna.
Então não
dar o que você precisa e apontar para o elemento zero da coluna da primeira linha da matriz?
Edit: pensando um pouco mais sobre isso, não é um nome de array, por definição, um ponteiro? Ou seja, o nome de uma matriz é um sinônimo para a localização do primeiro elemento, ou seja, l_matrix [0] [0]?
Edit2: Como mencionado por outros, o espaço de comentários é um pouco pequeno para uma discussão mais aprofundada. De qualquer forma:
não fornece nenhuma alocação de armazenamento para o array em questão.
Conforme mencionado acima, e conforme definido pela norma, a declaração:
reservou 200 locais sequenciais do tipo uint8_t.
Referindo-se a l_matrix usando instruções da forma:
fornecerá o conteúdo do elemento colno'th encontrado na linha rowno.
Este também é o caso se qualquer deslocamento de preenchimento ou alinhamento de byte estiver envolvido no armazenamento do objeto em questão. O compilador se ajustará automaticamente para eles. Por definição do padrão C ANSI.
HTH
Felicidades,
fonte
Em C99 (compatível com clang e gcc), há uma sintaxe obscura para a passagem de matrizes multidimensionais para funções por referência:
Ao contrário de um ponteiro simples, isso sugere o tamanho do array, teoricamente permitindo que o compilador avise sobre a passagem de um array muito pequeno e identifique o acesso fora dos limites.
Infelizmente, ele não corrige
sizeof()
e os compiladores parecem não usar essa informação ainda, então continua sendo uma curiosidade.fonte
static 10
é algum tipo de garantia de que pelo menos 10 elementos estão presentes, o que novamente significa que o tamanho não é fixo.static
, o array não seria passado por referência, o que não é verdade. Os arrays são passados por referência de qualquer maneira. A pergunta original era sobre um caso de uso diferente - acessando elementos de array 2D usando um ponteiro suplementar dentro da mesma função / namespace.Você sempre pode evitar mexer no compilador declarando o array como linear e fazendo o (linha, col) para o cálculo do índice do array você mesmo.
isso é o que o compilador teria feito de qualquer maneira.
fonte
A sintaxe básica do ponteiro de inicialização que aponta para a matriz multidimensional é
type (*pointer)[1st dimension size][2nd dimension size][..] = &array_name
A sintaxe básica para chamá-lo é
Aqui está um exemplo:
O resultado é:
Funcionou...
fonte
Você pode fazer assim:
fonte
Você quer um ponteiro para o primeiro elemento, então;
fonte
Você também pode adicionar um deslocamento se quiser usar índices negativos:
Se o seu compilador fornecer um erro ou aviso, você pode usar:
fonte
c
, portanto, a resposta deve estar no mesmo idioma. Observe as tags.