216 votes

Comment sont multi-dimensions des tableaux formatés en mémoire?

En C, je sais que je peux allouer dynamiquement un tableau à deux dimensions sur le tas en utilisant le code suivant:

int** someNumbers = malloc(arrayRows*sizeof(int*));

for (i = 0; i < arrayRows; i++) {
    someNumbers[i] = malloc(arrayColumns*sizeof(int));
}

Clairement, cela crée un tableau à une dimension de pointeurs sur un tas de séparer une dimensions des tableaux d'entiers, et "Le Système" peut comprendre ce que je veux dire quand je demande:

someNumbers[4][2];

Mais quand je statiquement déclarer un tableau 2D, comme dans la ligne suivante...:

int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];

...une structure similaire créé sur la pile, ou est-il d'une autre forme complètement? (c'est à dire est-il un 1D tableau de pointeurs? Si non, quel est-il et comment faire pour les références obtenez compris?)

Aussi, quand j'ai dit, "Le Système", ce qui est réellement responsable de le comprendre? Le noyau? Ou ne le compilateur C de faire le tri lors de la compilation?

174voto

Carl Norum Points 114072

Statique tableau à deux dimensions ressemble à un tableau de tableaux - c'est juste disposées de manière contiguë en mémoire. Les tableaux ne sont pas la même chose que les pointeurs, mais parce que vous pouvez souvent utiliser à peu près de façon interchangeable, il peut devenir confus parfois. Le compilateur permet de suivre correctement, cependant, ce qui rend tout le line-up bien. Vous ne devez être prudent avec statique 2D tableaux comme vous le mentionnez, car si vous essayez de passer à une fonction prenant un int ** paramètre, les mauvaises choses vont arriver. Voici un exemple rapide:

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

En mémoire ressemble à ceci:

0 1 2 3

exactement la même chose que:

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

Mais si vous essayez de passer array1 de cette fonction:

void function1(int **a);

vous recevrez un avertissement (et l'application ne parviennent pas à accéder au tableau correctement):

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

Parce que d'un tableau 2D n'est pas le même que int **. Le automatique de la décomposition d'une matrice en un pointeur ne va "d'un niveau de profondeur" pour ainsi dire. Vous devez déclarer la fonction:

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

ou

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

Pour faire tout heureux.

Ce même concept s'étend à n-dimensions des tableaux. En prenant avantage de ce type de drôles d'affaires dans votre application, en général, seulement la rend plus difficile à comprendre, cependant. Donc faites attention.

91voto

caf Points 114951

La réponse est basée sur l'idée que le C n'a pas vraiment d' avoir des tableaux 2D - il a des tableaux de tableaux. Lorsque vous déclarer ceci:

int someNumbers[4][2];

Vous demandez someNumbers être un tableau de 4 éléments, où chaque élément de ce tableau est de type int [2] (qui est lui-même un tableau de 2 ints).

L'autre partie de l'énigme est que les tableaux sont toujours disposés de manière contiguë en mémoire. Si vous demandez:

sometype_t array[4];

alors ce sera toujours ressembler à ceci:

| sometype_t | sometype_t | sometype_t | sometype_t |

(4 sometype_t objets disposés les uns à côté des autres, sans espaces entre les deux). Donc, dans votre someNumbers tableau de tableaux, ça va ressembler à ceci:

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

Et chaque int [2] élément est lui-même un tableau, qui ressemble à ceci:

| int        | int        |

Donc dans l'ensemble, vous obtenez ceci:

| int | int  | int | int  | int | int  | int | int  |

32voto

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

la mémoire est égale à:

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

5voto

Jon L Points 198

En réponse à votre également: les Deux, bien que le compilateur fait le plus de soulever des poids lourds.

Dans le cas de la statique des tableaux, "Le Système" est le compilateur. Il réserve la mémoire, comme il le ferait pour tout pile variable.

Dans le cas de la malloc avais tableau, "Le Système" sera le responsable de l'implémentation de malloc (le noyau). Tout le compilateur alloue est le pointeur de la base.

Le compilateur est toujours va gérer le type que ce qu'ils sont déclarés à l'exception, dans l'exemple de Carl donné où il peut comprendre interchangeables d'utilisation. C'est pourquoi, si vous passez dans un [][] pour une fonction qu'il doit supposer que c'est un allouée statiquement plat, où ** est supposé être un pointeur de pointeur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X