Je sais qu'il y a plusieurs questions à ce sujet qui donnent de bonnes solutions (et qui fonctionnent), mais aucune à mon humble avis qui dit clairement quelle est la meilleure façon d'y parvenir. Supposons donc que nous ayons un tableau 2D:
int tab1[100][280];
Nous voulons créer 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 bien :
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:
//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
produit le même binaire sauf les 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 le tableau tab1
est utilisé dans un corps de fonction => ce tableau sera placé dans la mémoire de la pile d'appels. Mais la taille de la pile est limitée. L'utilisation de tableaux plus grands que la pile de mémoire libre produit un débordement de pile crash .
L'extrait complet est compilable en ligne sur 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 un 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.
Pour en venir à 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 int (*pointer)[280];
est incrémenté, alors il pointe vers le tableau 1D suivant, mais là où int (*pointer)[100][280];
traverse le tableau 2D tout entier et pointe vers l'octet suivant. L'accès à cet octet peut poser problème 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 attribuez en fait la première ligne de tab1
. Cela fonctionne car 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 (pointer[5]
est de type int[280]
), il y a donc un autre implicite transtypé 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 rapidement. Sous le capot, les deux pointeurs pointent même vers le même emplacement mémoire (le premier élément du tab1
array), et 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 approfondie du fonctionnement des tableaux et des pointeurs en C pour comprendre ce qui se passe. Le second est plus explicite.