Cet idiome tombe naturellement de 1D allocation de tableau. Commençons par l'allocation d'un tableau 1D de certains type arbitraire T
:
T *p = malloc( sizeof *p * N );
Simple, non? L' expression *p
type T
, alors sizeof *p
donne le même résultat que l' sizeof (T)
, nous sommes donc d'allouer assez d'espace pour un N
-élément de tableau de T
. Cela est vrai pour n'importe quel type T
.
Maintenant, nous allons remplacer T
avec un type tableau comme R [10]
. Ensuite, notre allocation devient
R (*p)[10] = malloc( sizeof *p * N);
La sémantique ici sont exactement les mêmes que les 1D méthode de répartition; tout ce qui a changé, c'est le type d' p
. Au lieu de T *
, il est maintenant de R (*)[10]
. L'expression *p
type T
qui est de type R [10]
, alors sizeof *p
est équivalent à sizeof (T)
ce qui est équivalent à sizeof (R [10])
. Nous sommes donc d'allouer assez d'espace pour un N
par 10
élément de tableau de R
.
Nous pouvons prendre encore plus loin si nous voulons; supposons R
est lui-même un tableau de type int [5]
. Un substitut pour R
et nous obtenons
int (*p)[10][5] = malloc( sizeof *p * N);
De même, le face - sizeof *p
est le même que sizeof (int [10][5])
, et nous avons le vent en place d'allouer un espace contigu de mémoire assez grande pour contenir une N
par 10
par 5
tableau d' int
.
Donc, c'est la répartition de côté; ce que sur le côté d'accès?
Rappelez-vous que l' []
indice fonctionnement est défini dans les termes de l'arithmétique des pointeurs: a[i]
est défini comme *(a + i)
1. Ainsi, l'indice de l'opérateur []
implicitement déréférence un pointeur. Si p
est un pointeur vers T
, vous pouvez accéder à la pointue de valeur, soit en faisant explicitement référence à l'unaire *
opérateur:
T x = *p;
ou en utilisant l' []
indice de l'opérateur:
T x = p[0]; // identical to *p
Ainsi, si p
points pour le premier élément d'un tableau, vous pouvez accéder à tout élément de ce tableau à l'aide d'un indice sur le pointeur p
:
T arr[N];
T *p = arr; // expression arr "decays" from type T [N] to T *
...
T x = p[i]; // access the i'th element of arr through pointer p
Maintenant, nous allons faire de notre opération de substitution de nouveau et remplacez - T
avec le type du tableau R [10]
:
R arr[N][10];
R (*p)[10] = arr; // expression arr "decays" from type R [N][10] to R (*)[10]
...
R x = (*p)[i];
Une différence immédiatement apparente; nous sommes explicitement référence p
avant l'application de l'indice de l'opérateur. Nous ne voulons pas d'indice en p
, nous voulons indice en ce qui p
de points à (dans ce cas, la matrice arr[0]
). Depuis unaire *
a priorité moins élevée que l'indice []
de l'opérateur, il faut utiliser des parenthèses pour explicitement groupe p
avec *
. Mais rappelez-vous, d'en haut, *p
est le même que p[0]
, donc on peut remplacer qu'avec
R x = (p[0])[i];
ou tout simplement
R x = p[0][i];
Ainsi, si p
de points à un tableau 2D, nous pouvons indice dans ce tableau via p
comme:
R x = p[i][j]; // access the i'th element of arr through pointer p;
// each arr[i] is a 10-element array of R
La prise de ce à la même conclusion que ci-dessus et de le remplacer par R
avec int [5]
:
int arr[N][10][5];
int (*p)[10][5]; // expression arr "decays" from type int [N][5][10] to int (*)[10][5]
...
int x = p[i][j][k];
Cela fonctionne tout de même si p
de points à un réseau régulier, ou si elle pointe vers la mémoire allouée par le biais malloc
.
Cet idiome a les avantages suivants:
- C'est simple - il suffit d'une seule ligne de code, par opposition à l'fragmentaire de la méthode de répartition
T **arr = malloc( sizeof *arr * N );
if ( arr )
{
for ( size_t i = 0; i < N; i++ )
{
arr[i] = malloc( sizeof *arr[i] * M );
}
}
- Toutes les lignes de la répartition de la matrice sont *contigus*, ce qui n'est pas le cas avec le fragmentaire de la méthode de répartition ci-dessus;
- Libérer le tableau est tout aussi facile avec un seul appel à
free
. Encore une fois, pas vrai avec le fragmentaire de la méthode de répartition, où vous devez libérer chaque arr[i]
avant de pouvoir libérer arr
.
Parfois fragmentaires, de la méthode de répartition est préférable, comme quand votre tas est très fragmenté et vous ne pouvez pas allouer la mémoire comme un espace contigu, ou que vous souhaitez allouer un "irréguliers" tableau où chaque ligne peut avoir une longueur différente. Mais en général, c'est la meilleure façon d'aller.
1. Rappelez-vous que les tableaux ne sont pas des pointeurs - au lieu de cela, tableau expressions sont convertis pointeur expressions comme nécessaire.