C pointeur vers un tableau bidimensionnel
Je sais qu'il y a plusieurs questions sur ce qui donne de bonnes solutions (et de travail), mais aucun à mon humble avis qui dit clairement quelle est la meilleure façon d'y parvenir. Donc, supposons que nous ayons un tableau 2D:
int tab1[100][280];
, Nous voulons faire un pointeur qui pointe vers ce tableau 2D. Pour y parvenir, nous pouvons faire:
int (*pointer)[280]; // pointer creation
pointer = tab1; //assignation
pointer[5][12] = 517; // use
int myint = pointer[5][12]; // use
, Ou, alternativement :
int (*pointer)[100][280]; // pointer creation
pointer = &tab1; //assignation
(*pointer)[5][12] = 517; // use
int myint = (*pointer)[5][12]; // use
OK, les deux semblent bien fonctionner. Maintenant, je voudrais savoir :
- Quelle est la meilleure façon, la 1ère ou la 2ème ?
- sont les deux égaux pour le compilateur ? (la vitesse, la perf...)
- l'une de ces solutions mange-t-elle plus de mémoire que l'autre ?
- quel est le plus fréquemment utilisé par les développeurs ?
3 réponses
//defines an array of 280 pointers (1120 or 2240 bytes)
int *pointer1 [280];
//defines a pointer (4 or 8 bytes depending on 32/64 bits platform)
int (*pointer2)[280]; //pointer to an array of 280 integers
int (*pointer3)[100][280]; //pointer to an 2D array of 100*280 integers
En utilisant pointer2
ou pointer3
produire le même binaire sauf manipulations que ++pointer2
comme indiqué par WhozCraig.
Je recommande d'utiliser typedef
(produisant le même code binaire que ci-dessus pointer3
)
typedef int myType[100][280];
myType *pointer3;
Remarque: Depuis C++11, vous pouvez également utiliser le mot-clé using
au lieu de typedef
using myType = int[100][280];
myType *pointer3;
Dans votre exemple:
myType *pointer; // pointer creation
pointer = &tab1; // assignation
(*pointer)[5][12] = 517; // set (write)
int myint = (*pointer)[5][12]; // get (read)
Remarque: Si la matrice tab1
est utilisé dans un corps de fonction => ce tableau sera placé dans la pile d'appel de la mémoire. Mais la taille de la pile est limitée. L'utilisation de tableaux plus grands que la pile de mémoire libre produit un la pile débordement crash .
L'extrait complet est compilable en ligne à gcc.godbolt.org
int main()
{
//defines an array of 280 pointers (1120 or 2240 bytes)
int *pointer1 [280];
static_assert( sizeof(pointer1) == 2240, "" );
//defines a pointer (4 or 8 bytes depending on 32/64 bits platform)
int (*pointer2)[280]; //pointer to an array of 280 integers
int (*pointer3)[100][280]; //pointer to an 2D array of 100*280 integers
static_assert( sizeof(pointer2) == 8, "" );
static_assert( sizeof(pointer3) == 8, "" );
// Use 'typedef' (or 'using' if you use a modern C++ compiler)
typedef int myType[100][280];
//using myType = int[100][280];
int tab1[100][280];
myType *pointer; // pointer creation
pointer = &tab1; // assignation
(*pointer)[5][12] = 517; // set (write)
int myint = (*pointer)[5][12]; // get (read)
return myint;
}
int *pointer[280];
//Crée 280 pointeurs de type int.
Dans le système d'exploitation 32 bits, 4 octets pour chaque pointeur. donc 4 * 280 = 1120 octets.
int (*pointer)[100][280];
// crée un seul pointeur qui est utilisé pour pointer un tableau de[100] [280] ints.
Ici seulement 4 octets.
En venant à votre question, int (*pointer)[280];
et int (*pointer)[100][280];
sont différents bien qu'ils pointent vers le même tableau 2D de [100] [280].
Parce que si {[2] } est incrémenté, alors il pointe vers le tableau 1D suivant, mais où int (*pointer)[100][280];
traverse tout le tableau 2D et les points à l'octet suivant. L'accès à cet octet peut causer des problèmes si cette mémoire n'appartient pas à votre processus.
Vos deux exemples sont équivalents. Cependant, le premier est moins évident et plus "hacky", tandis que le second indique clairement votre intention.
int (*pointer)[280];
pointer = tab1;
pointer
pointe vers un tableau 1D de 280 entiers. Dans votre affectation, vous affectez en fait la première ligne de tab1
. Cela fonctionne puisque vous pouvez implicitement convertir des tableaux en pointeurs (vers le premier élément).
Lorsque vous utilisez pointer[5][12]
, C traite pointer
comme un tableau de tableaux ({[6] } est de type int[280]
), donc il y a un autreimplicite jeté ici (au moins sémantiquement).
Dans votre deuxième exemple, vous créez explicitement un pointeur vers un tableau 2D:
int (*pointer)[100][280];
pointer = &tab1;
La sémantique est plus claire ici: *pointer
est un tableau 2D, vous devez donc y accéder en utilisant (*pointer)[i][j]
.
Les deux solutions utilisent la même quantité de mémoire (1 pointeur) et fonctionneront probablement aussi vite. Sous le capot, les deux pointeurs pointeront même vers le même emplacement de mémoire (le premier élément du tableau tab1
), et c'est il est possible que votre compilateur génère même le même code.
La première solution est "plus avancée" car il faut une compréhension assez profonde du fonctionnement des tableaux et des pointeurs en C pour comprendre ce qui se passe. Le deuxième est plus explicite.