Pergunta

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 variedade unidimensional de ponteiros para um monte de matrizes unidimensionais separadas de números inteiros, e "o sistema" pode descobrir o que quero dizer quando peço:

someNumbers[4][2];

Mas quando declaro estaticamente uma matriz 2D, como na linha seguinte ...:

int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];

... Uma estrutura semelhante é criada na pilha ou é de outra forma completamente? (ou seja, é uma variedade 1D de ponteiros? Se não, o que é e como as referências 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 classifica enquanto compilação?

Foi útil?

Solução

Uma matriz bidimensional estática parece uma matriz de matrizes - é apenas disputada de maneira contígua. As matrizes não são a mesma coisa que os ponteiros, mas como você pode usá -los praticamente de forma intercambiável, às vezes pode ficar confuso. O compilador mantém a pista corretamente, o que faz tudo se alinhar bem. Você precisa ter cuidado com matrizes 2D estáticas como mencionar, pois se você tentar passar um para uma função tomando um int ** Parâmetro, coisas ruins vão acontecer. Aqui está um exemplo rápido:

int array1[3][2] = {{0, 1}, {2, 3}, {4, 5}};

Na memória se parece com o seguinte:

0 1 2 3 4 5

exatamente o mesmo que:

int array2[6] = { 0, 1, 2, 3, 4, 5 };

Mas se você tentar passar array1 para esta função:

void function1(int **a);

Você receberá um aviso (e o aplicativo deixará de acessar a matriz corretamente):

warning: passing argument 1 of ‘function1’ from incompatible pointer type

Porque uma matriz 2D não é a mesma que int **. A decomposição automática de uma matriz em um ponteiro só vai "um nível de profundidade", por assim dizer. Você precisa declarar a função como:

void function2(int a[][2]);

ou

void function2(int a[3][2]);

Para fazer tudo feliz.

Esse mesmo conceito se estende a nMatrizes dimensionais. Aproveitar esse tipo de negócio engraçado em seu aplicativo geralmente apenas torna mais difícil de entender. Portanto, tenha cuidado lá fora.

Outras dicas

A resposta é baseada na ideia de que C realmente não tenho Matrizes 2D-tem matrizes de marcas. Quando você declara isso:

int someNumbers[4][2];

Você está pedindo someNumbers ser uma matriz de 4 elementos, onde cada elemento dessa matriz é do tipo int [2] (que é em si uma matriz de 2 ints).

A outra parte do quebra -cabeça é que as matrizes são sempre estabelecidas contiguamente na memória. Se você pedir:

sometype_t array[4];

Então isso sempre ficará assim:

| sometype_t | sometype_t | sometype_t | sometype_t |

(4 sometype_t objetos estabelecidos um ao lado do outro, sem espaços intermediários). Então, em seu someNumbers Matriz de marcas, será assim:

| int [2]    | int [2]    | int [2]    | int [2]    |

E cada um int [2] O elemento é uma matriz, que se parece com o seguinte:

| int        | int        |

Então, no geral, você entendeu:

| int | int  | int | int  | int | int  | int | int  |
unsigned char MultiArray[5][2]={{0,1},{2,3},{4,5},{6,7},{8,9}};

na memória é igual a:

unsigned char SingleArray[10]={0,1,2,3,4,5,6,7,8,9};

Em resposta ao seu também: ambos, embora o compilador esteja fazendo a maior parte do levantamento pesado.

No caso de matrizes alocadas estaticamente, "o sistema" será o compilador. Reservará a memória como faria em qualquer variável de pilha.

No caso da matriz MaiC'd, "o sistema" será o implementador do Malloc (o kernel normalmente). Todo o compilador alocará é o ponteiro base.

O compilador sempre lidará com o tipo, pois o que eles são declarados, exceto no exemplo que Carl deu onde pode descobrir o uso intercambiável. É por isso que, se você passa em um [] [] para uma função, deve assumir que é um apartamento alocado estaticamente, onde ** é considerado um ponteiro para o ponteiro.

Para acessar uma matriz 2D específica, considere o mapa de memória para uma declaração de matriz, como mostrado no código abaixo:

    0  1
a[0]0  1
a[1]2  3

Para acessar cada elemento, é suficiente apenas passar em qual matriz você está interessado como parâmetros da função. Em seguida, use deslocamento para a coluna para acessar cada elemento individualmente.

int a[2][2] ={{0,1},{2,3}};

void f1(int *ptr);

void f1(int *ptr)
{
    int a=0;
    int b=0;
    a=ptr[0];
    b=ptr[1];
    printf("%d\n",a);
    printf("%d\n",b);
}

int main()
{
   f1(a[0]);
   f1(a[1]);
    return 0;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top