J'ai besoin d'un pointeur vers un tableau statique à 2 dimensions. Comment cela se fait-il?
static uint8_t l_matrix[10][20];
void test(){
uint8_t **matrix_ptr = l_matrix; //wrong idea
}
J'obtiens toutes sortes d'erreurs comme:
- avertissement: affectation d'un type de pointeur incompatible
- la valeur en indice n'est ni un tableau ni un pointeur
- erreur: utilisation incorrecte du membre du tableau flexible
Réponses:
Ici, vous voulez faire un pointeur vers le premier élément du tableau
Avec typedef, cela semble plus propre
Ensuite, vous pourrez à nouveau profiter de la vie :)
Méfiez-vous du monde pointeur / tableau en C, il y a beaucoup de confusion autour de cela.
Éditer
Passez en revue certaines des autres réponses ici, car les champs de commentaire sont trop courts pour y figurer. Plusieurs alternatives ont été proposées, mais on n'a pas montré comment elles se comportent. Voici comment ils font
Si vous corrigez l'erreur et ajoutez l'opérateur address-of
&
comme dans l'extrait suivantEnsuite, celui-ci crée un pointeur vers un tableau de type incomplet d'éléments de type tableau de 20 uint8_t. Comme le pointeur est vers un tableau de tableaux, vous devez y accéder avec
Et comme il s'agit d'un pointeur vers un tableau incomplet, vous ne pouvez pas faire de raccourci
Parce que l'indexation nécessite que la taille du type d'élément soit connue (l'indexation implique l'ajout d'un entier au pointeur, donc cela ne fonctionnera pas avec les types incomplets). Notez que cela ne fonctionne que dans
C
, carT[]
etT[N]
sont des types compatibles. C ++ n'a pas de concept de types compatibles , il rejettera donc ce code, carT[]
etT[10]
sont des types différents.L'alternative suivante ne fonctionne pas du tout, car le type d'élément du tableau, lorsque vous le visualisez comme un tableau unidimensionnel, ne l' est pas
uint8_t
, maisuint8_t[20]
Ce qui suit est une bonne alternative
Vous y accédez avec
Il a l'avantage de préserver la taille de la dimension extérieure. Vous pouvez donc y appliquer sizeof
Il existe une autre réponse qui utilise le fait que les éléments d'un tableau sont stockés de manière contiguë
Maintenant, cela ne vous permet formellement d'accéder qu'aux éléments du premier élément du tableau à deux dimensions. Autrement dit, la condition suivante est maintenue
Vous remarquerez que cela fonctionne probablement
10*20-1
, mais si vous lancez une analyse d'alias et d'autres optimisations agressives, certains compilateurs pourraient faire une hypothèse qui pourrait casser ce code. Cela dit, je n'ai jamais rencontré de compilateur qui échoue dessus (mais là encore, je n'ai pas utilisé cette technique dans du code réel), et même la FAQ C contient cette technique (avec un avertissement sur son UB'ness ), et si vous ne pouvez pas changer le type de tableau, c'est une dernière option pour vous sauver :)la source
uint8_t *d[20]
, qui crée un tableau de 3 pointeurs vers uint8_t, mais cela ne fonctionnerait pas dans ce cas.Pour bien comprendre cela, vous devez comprendre les concepts suivants:
Les tableaux ne sont pas des pointeurs!
Tout d'abord (et cela a été assez prêché), les tableaux ne sont pas des pointeurs . Au lieu de cela, dans la plupart des utilisations, ils `` se désintègrent '' vers l'adresse de leur premier élément, qui peut être attribué à un pointeur:
Je suppose que cela fonctionne de cette manière afin que le contenu du tableau soit accessible sans les copier tous. C'est juste un comportement de types de tableaux et ne veut pas dire qu'ils sont la même chose.
Tableaux multidimensionnels
Les tableaux multidimensionnels ne sont qu'un moyen de «partitionner» la mémoire d'une manière que le compilateur / la machine peut comprendre et utiliser.
Par exemple,
int a[4][3][5]
= un tableau contenant 4 * 3 * 5 (60) «morceaux» de mémoire de taille entière.L'avantage sur l'utilisation de
int a[4][3][5]
vs plainint b[60]
est qu'ils sont maintenant «partitionnés» (il est plus facile de travailler avec leurs «morceaux», si nécessaire), et le programme peut maintenant effectuer une vérification liée.En fait,
int a[4][3][5]
est stocké exactement commeint b[60]
dans la mémoire - La seule différence est que le programme le gère maintenant comme s'il s'agissait d'entités séparées de certaines tailles (plus précisément, quatre groupes de trois groupes de cinq).Gardez à l'esprit: les deux
int a[4][3][5]
etint b[60]
sont identiques en mémoire, et la seule différence est la façon dont ils sont gérés par l'application / le compilateurÀ partir de là, vous pouvez clairement voir que chaque «partition» est juste un tableau dont le programme effectue le suivi.
Syntaxe
Désormais, les tableaux sont syntaxiquement différents des pointeurs . Plus précisément, cela signifie que le compilateur / la machine les traitera différemment. Cela peut sembler une évidence, mais jetez un œil à ceci:
L'exemple ci-dessus imprime deux fois la même adresse mémoire, comme ceci:
Cependant, un seul peut être affecté à un pointeur aussi directement :
Pourquoi ne peut pas
a
être affecté à un pointeur maisa[0]
peut?Ceci, simplement, est une conséquence des tableaux multidimensionnels, et je vais vous expliquer pourquoi:
Au niveau de «
a
», nous voyons toujours que nous avons une autre «dimension» à espérer. Au niveau de 'a[0]
', cependant, nous sommes déjà dans la dimension supérieure, donc en ce qui concerne le programme, nous ne regardons qu'un tableau normal.Vous demandez peut-être:
Pourquoi est-il important que le tableau soit multidimensionnel en ce qui concerne la création d'un pointeur pour lui?
Il vaut mieux penser de cette façon:
Une `` désintégration '' d'un tableau multidimensionnel n'est pas seulement une adresse, mais une adresse avec des données de partition (AKA, elle comprend toujours que ses données sous-jacentes sont constituées d'autres tableaux), qui se compose de limites définies par le tableau au-delà de la première dimension.
Cette logique de 'partition' ne peut pas exister dans un pointeur sauf si nous la spécifions:
Sinon, la signification des propriétés de tri du tableau est perdue.
Notez également l'utilisation de parenthèses autour de
*p
:int (*p)[5][95][8]
- C'est pour spécifier que nous faisons un pointeur avec ces limites, pas un tableau de pointeurs avec ces limites:int *p[5][95][8]
Conclusion
Revoyons:
En bref: les tableaux multidimensionnels se désintègrent en adresses qui permettent de comprendre leur contenu.
la source
int *p1 = &(a[0]); // RIGHT !
fait, il est identique àint *p1 = a;
Dans
vous pouvez accéder comme
après que tous les tableaux à 2 dimensions sont également stockés en 1-d.
la source
G'day,
La déclaration
a réservé un espace de stockage pour 10 lignes de 20 emplacements unit8_t, soit 200 emplacements de taille uint8_t, chaque élément étant trouvé en calculant 20 x ligne + colonne.
Donc pas
vous donner ce dont vous avez besoin et pointer vers l'élément de la colonne zéro de la première ligne du tableau?
Edit: En y réfléchissant un peu plus loin, un nom de tableau, par définition, n'est-il pas un pointeur? Autrement dit, le nom d'un tableau est un synonyme de l'emplacement du premier élément, ie l_matrix [0] [0]?
Edit2: Comme mentionné par d'autres, l'espace de commentaire est un peu trop petit pour une discussion plus approfondie. En tous cas:
ne fournit aucune allocation de stockage pour la baie en question.
Comme mentionné ci-dessus, et tel que défini par la norme, la déclaration:
a mis de côté 200 emplacements séquentiels de type uint8_t.
Se référant à l_matrix en utilisant des déclarations de la forme:
vous donnera le contenu de l'élément colno'th trouvé dans la ligne rowno.
C'est également le cas si un remplissage ou un décalage d'alignement d'octets est impliqué dans le stockage de l'objet à portée de main. Le compilateur les ajustera automatiquement.Par définition de la norme C ANSI.
HTH
à votre santé,
la source
En C99 (pris en charge par clang et gcc), il existe une syntaxe obscure pour passer des tableaux multidimensionnels aux fonctions par référence:
Contrairement à un pointeur simple, cela donne des indications sur la taille du tableau, permettant théoriquement au compilateur d'avertir du passage d'un tableau trop petit et de repérer les accès hors limites évidents.
Malheureusement, cela ne résout pas
sizeof()
et les compilateurs ne semblent pas encore utiliser ces informations, cela reste donc une curiosité.la source
static 10
est une sorte de garantie qu'au moins 10 éléments sont présents, ce qui signifie encore une fois que la taille n'est pas fixe.static
, le tableau ne serait pas passé par référence, ce qui n'est pas vrai. Les tableaux sont de toute façon passés par référence. La question originale portait sur un cas d'utilisation différent - accéder aux éléments d'un tableau 2D à l'aide d'un pointeur supplémentaire dans la même fonction / espace de noms.Vous pouvez toujours éviter de manipuler le compilateur en déclarant le tableau comme linéaire et en effectuant vous-même le calcul d'index (ligne, col) au tableau.
c'est ce que le compilateur aurait fait de toute façon.
la source
La syntaxe de base du pointeur d'initialisation qui pointe vers un tableau multidimensionnel est
type (*pointer)[1st dimension size][2nd dimension size][..] = &array_name
La syntaxe de base pour l'appeler est
Voici un exemple:
La sortie est:
Ça a marché...
la source
Vous pouvez le faire comme ceci:
la source
Vous voulez un pointeur sur le premier élément, donc;
la source
Vous pouvez également ajouter un décalage si vous souhaitez utiliser des index négatifs:
Si votre compilateur donne une erreur ou un avertissement, vous pouvez utiliser:
la source
c
, donc la réponse doit être dans la même langue. Veuillez observer les balises.