Em C, eu sei que posso alocar dinamicamente uma matriz bidimensional na pilha usando o seguinte código:
int** someNumbers = malloc(arrayRows*sizeof(int*));
for (i = 0; i < arrayRows; i++) {
someNumbers[i] = malloc(arrayColumns*sizeof(int));
}
Claramente, isso realmente cria uma matriz unidimensional de ponteiros para várias matrizes unidimensionais separadas de números inteiros, e "O sistema" pode entender o que quero dizer quando solicito:
someNumbers[4][2];
Mas quando declaro estaticamente uma matriz 2D, como na seguinte linha ...:
int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];
... uma estrutura semelhante é criada na pilha ou é de outra forma completamente? (ou seja, é um conjunto de ponteiros 1D? Se não, o que é e como as referências a ele são descobertas?)
Além disso, quando eu disse: "O sistema", o que é realmente responsável por descobrir isso? O kernel? Ou o compilador C resolve isso enquanto compila?
c
arrays
memory
data-structures
stack-memory
Chris Cooper
fonte
fonte
malloc()
não resultam em uma matriz N-dimensional. . Isso resulta em matrizes de ponteiros [para matrizes de ponteiros [...]] para separar completamente matrizes unidimensionais . Consulte Alocação correta de matrizes multidimensionais para ver como alocar TRUE matriz N-dimensional.Respostas:
Uma matriz bidimensional estática se parece com uma matriz de matrizes - é apenas apresentada de forma contígua na memória. Matrizes não são a mesma coisa que ponteiros, mas como você pode frequentemente usá-las de maneira intercambiável, às vezes pode ficar confuso. O compilador mantém o controle adequadamente, o que faz com que tudo seja alinhado de maneira agradável. Você precisa ter cuidado com matrizes 2D estáticas como você mencionou, pois se você tentar passar uma para uma função usando um
int **
parâmetro, coisas ruins vão acontecer. Aqui está um exemplo rápido:Na memória, fica assim:
exatamente o mesmo que:
Mas se você tentar passar
array1
para esta função:você receberá um aviso (e o aplicativo não conseguirá acessar a matriz corretamente):
Porque uma matriz 2D não é a mesma que
int **
. O decaimento automático de uma matriz em um ponteiro atinge apenas "um nível de profundidade", por assim dizer. Você precisa declarar a função como:ou
Para fazer tudo feliz.
Esse mesmo conceito se estende a matrizes n- dimensionais. Porém, tirar proveito desse tipo de negócio engraçado em seu aplicativo geralmente dificulta a compreensão. Portanto, tenha cuidado lá fora.
fonte
sizeof(int[100]) != sizeof(int *)
(a menos que você encontre uma plataforma com100 * sizeof(int)
bytes /int
, mas isso é uma coisa diferente.A resposta é baseada na ideia de que C realmente não possui matrizes 2D - ele possui matrizes de matrizes. Quando você declara isso:
Você está solicitando
someNumbers
uma matriz de 4 elementos, em que cada elemento dessa matriz é do tipoint [2]
(que é uma matriz de 2int
s).A outra parte do quebra-cabeça é que as matrizes são sempre dispostas contiguamente na memória. Se você pedir:
então isso sempre será assim:
(4
sometype_t
objetos dispostos um ao lado do outro, sem espaços entre eles). Portanto, na suasomeNumbers
matriz de matrizes, ficará assim:E cada
int [2]
elemento é ele próprio uma matriz, que se parece com isso:Então, no geral, você obtém o seguinte:
fonte
int
na matriz de matrizes (por exemplo, avaliandoa[0]
ou&a[0][0]
), então sim, você pode compensar isso para acessar todos os seqüencialmenteint
).na memória é igual a:
fonte
Em resposta à sua também: Ambos, embora o compilador esteja fazendo a maior parte do trabalho pesado.
No caso de matrizes alocadas estaticamente, "O Sistema" será o compilador. Ele reservará a memória como faria para qualquer variável de pilha.
No caso da matriz malloc'd, "The System" será o implementador do malloc (normalmente o kernel). Tudo o que o compilador alocará é o ponteiro base.
O compilador sempre manipulará o tipo como ele é declarado, exceto no exemplo que Carl deu, onde ele pode descobrir o uso intercambiável. É por isso que se você passa um [] [] para uma função, ele deve assumir que é um apartamento alocado estaticamente, onde ** é assumido como ponteiro para ponteiro.
fonte
malloc
é implementado não é especificado pelo padrão e deixado para a implementação, resp. meio Ambiente. Para ambientes independentes, é opcional, como todas as partes da biblioteca padrão que requerem funções de vinculação (é nisso que os requisitos realmente resultam, não literalmente no que o padrão declara). Para alguns ambientes hospedados modernos, ele realmente depende das funções do kernel, ou do material completo, ou (por exemplo, Linux), como você escreveu usando stdlib e primitivos do kernel. Para sistemas de processo único de memória não virtual, ele pode ser apenas stdlib.Suponha, temos
a1
ea2
definido e inicializado como abaixo (C99):a1
é uma matriz 2D homogênea com layout contínuo simples na memória e a expressão(int*)a1
é avaliada em um ponteiro para seu primeiro elemento:a2
é inicializado a partir de uma matriz 2D heterogênea e é um ponteiro para um valor do tipoint*
, ou seja, a expressão de desreferência é*a2
avaliada em um valor do tipoint*
, o layout da memória não precisa ser contínuo:Apesar do layout de memória e da semântica de acesso totalmente diferentes, a gramática da linguagem C para expressões de acesso à matriz é exatamente a mesma para a matriz 2D homogênea e heterogênea:
a1[1][0]
buscará valor144
fora daa1
matriza2[1][0]
buscará valor244
fora daa2
matrizO compilador sabe que a expressão de acesso para
a1
opera no tipoint[2][2]
, quando a expressão de acesso paraa2
opera no tipoint**
. O código de montagem gerado seguirá a semântica de acesso homogênea ou heterogênea.O código geralmente falha no tempo de execução quando a matriz do tipo
int[N][M]
é convertida em tipo e depois acessada como tipoint**
, por exemplo:fonte
Para acessar uma matriz 2D específica, considere o mapa de memória para uma declaração de matriz, conforme mostrado no código abaixo:
Para acessar cada elemento, basta passar em qual array você está interessado como parâmetros para a função. Em seguida, use deslocamento para a coluna para acessar cada elemento individualmente.
fonte