Adresse de pointeur en C tableau multidimensionnel
Je suis de déconner avec les tableaux multidimensionnels et des pointeurs. J'ai été à la recherche à un programme qui affiche le contenu d', et les adresses des, un simple tableau. Voici ma déclaration de tableau:
int zippo[4][2] = { {2,4},
{6,8},
{1,3},
{5,7} };
Ma compréhension est que zippo
est un pointeur, et il peut contenir l'adresse d'un couple d'autres pointeurs. Par défaut, zippo
contient l'adresse de pointeur zippo[0]
, et il peut également contenir les adresses des pointeurs zippo[1]
, zippo[2]
, et zippo[3]
.
Maintenant, prenez la déclaration suivante:
printf("zippo[0] = %p\n", zippo[0]);
printf(" *zippo = %p\n", *zippo);
printf(" zippo = %p\n", zippo);
Sur ma machine, qui donne le résultat suivant:
zippo[0] = 0x7fff170e2230
*zippo = 0x7fff170e2230
zippo = 0x7fff170e2230
J'ai parfaitement comprendre pourquoi zippo[0]
et *zippo
ont la même valeur. Ils sont tous les deux pointeurs, et ils ont à la fois de stocker l'adresse (par défaut) de l'entier 2, ou zippo[0][0]
. Mais ce qui est à zippo
aussi partage la même adresse mémoire? Ne devrait pas zippo
stocker l'adresse du pointeur zippo[0]
? Whaaaat?
- En fait, je n'ai jamais touché de Java. J'ai brièvement mettre mes pieds dans l'eau avec BASIC et pascal, puis a sauté à droite dans avec C. C est la première et la seule langue que j'ai jamais vraiment essayé d'apprentissage. Qu'est-ce que Java de niveau plus élevé, et n'a donc pas besoin de traiter avec ce niveau de détail?
Vous devez vous connecter pour publier un commentaire.
Lorsque vous déclarez un tableau multidimensionnel, le compilateur traite comme un seul tableau multidimensionnel. Les tableaux multidimensionnels sont qu'une abstraction pour rendre notre vie plus facile. Vous avez un malentendu: Ce n'est pas un tableau de pointage de 4 tableaux, c'est toujours un seul états contigus bloc de mémoire.
Dans votre cas, en faisant:
Est vraiment la même chose que de faire
Avec les maths pour le 2D addressing géré pour vous par le compilateur.
Pour plus de détails, voir cette tutoriel sur les Tableaux en C++.
C'est très différent que de le faire:
ou
Dans ce cas, tu fais un tableau de pointeurs quatre, ce qui pourrait être alloué à d'autres tableaux.
Lorsqu'un tableau de l'expression apparaît dans la plupart des contextes, son type est implicitement converti à partir "N-élément de tableau de T" à "pointeur de T", et sa valeur est définie pour pointer vers le premier élément dans le tableau. Les exceptions à cette règle lorsque la matrice d'expression est un opérande de l'
sizeof
ou de l'adresse de (&
) les opérateurs, ou lorsque le tableau est un littéral de chaîne utilisé comme un initialiseur dans une déclaration.Ainsi, l'expression
zippo
"désintègre" de typeint [4][2]
(4-élément de tableau de 2 éléments des tableaux de int) àint (*)[2]
(pointeur de 2-élément de tableau de int). De même, le type dezippo[0]
estint [2]
, qui est implicitement converti àint *
.Compte tenu de la déclaration
int zippo[4][2]
, le tableau suivant montre les différents types de tableau les expressions impliquant zippo et toutes les conversions implicites:Noter que
zippo
,&zippo
,*zippo
,zippo[0]
,&zippo[0]
, et&zippo[0][0]
ont tous la même valeur; ils ont tous le point à la base du tableau (l'adresse du tableau est la même que l'adresse du premier élément du tableau). Les types des différentes expressions sont tous différents, bien que.zippo
n'est pas un pointeur. C'est un tableau de tableau de valeurs.zippo
, etzippo[i]
pouri
dans 0..4 "chute" d'un pointeur dans certains cas (en particulier, la valeur des contextes). Essayez d'imprimersizeof zippo
pour un exemple de l'utilisation dezippo
en non-valeur de contexte. Dans ce cas,sizeof
fera rapport à la taille de la matrice, ce n'est pas la taille d'un pointeur.Le nom d'un tableau, en valeur des contextes, se désintègre en un pointeur sur son premier élément. Ainsi, dans le contexte de valeurs,
zippo
est le même que&zippo[0]
, et donc de type "pointeur sur un tableau [2] deint
";*zippo
, dans le contexte de valeurs est le même que&zippo[0][0]
, c'est à dire, "pointeur versint
". Ils ont la même valeur, mais de types différents.Je recommande la lecture de Les tableaux et les Pointeurs pour répondre à votre deuxième question. Les pointeurs ont la même "valeur", mais point à des montants différents de l'espace. Essayez d'imprimer
zippo+1
et*zippo+1
à voir plus clairement:Pour ma course, il imprime:
Me disant que
sizeof(int)
sur ma machine est de 4, et que la deuxième et la troisième les pointeurs ne sont pas de valeur égale (comme prévu).Aussi,
"%p"
spécificateur de format besoinsvoid *
dans*printf()
fonctions, de sorte que vous devriez jeter votre pointeurs versvoid *
dans votreprintf()
appels (printf()
est un variadic de la fonction, de sorte que le compilateur ne peut pas faire la conversion automatique pour vous ici).Modifier: Quand je dis un tableau "désintègre" à un pointeur, je veux dire que le nom d'une table dans le contexte de valeurs est équivalent à un pointeur. Donc, si j'ai
T pt[100];
pour certains type deT
, puis le nompt
est de typeT *
en valeur les contextes. Poursizeof
et unaires&
opérateurs, le nompt
ne pas réduire à un pointeur. Mais vous pouvez faireT *p = pt;
—ce qui est parfaitement valide parce que, dans ce contexte,pt
est de typeT *
.Noter que cette "décomposition" n'arrive qu'une fois. Alors, disons que nous avons:
Puis,
zippo
dans le contexte de valeurs se désintègre à un pointeur de type: pointeur vers tableau[2] deint
. Dans le code:est valable, alors que
va déclencher un "incompatible pointeur de la cession d'avertissement".
Avec
zippo
définis comme ci-dessus,sont toutes valides. Ils doivent imprimer la même valeur lors de l'impression à l'aide de
printf("%p\n", (void *)name);
, mais les pointeurs sont différents en ce qu'ils point à l'ensemble de la matrice, une ligne, et un seul entier respectivement.zippo
etzippo[0]
point à différentes quantités de mémoire, leur adresse de départ est la même, et la valeur des contextes ils seront à la fois de point de le premier entier dans zippo. - Il Correct? Et, est-ce que vous entendez par "décroissance"?zippo[0]
en valeur des contextes estint *
, et les points pour le premier entier, oùzippo
en valeur des contextes est "pointeur sur un tableau [2] deint
". Vous pourriez faire:int (*p)[2]; p = zippo;
par exemple. Ensuite,p[0] == 2
etp[1] == 4
. Pour la "décroissance", voir mon (bientôt le voir) edit.La chose importante ici est que
int zippy[4][2]
n'est pas le même type d'objet queint **zippo
.Comme
int zippi[5]
,zippy
est l'adresse d'un bloc de mémoire. Mais le compilateur sait que vous voulez l'adresse de huit emplacement de mémoire commençant àzippy
avec deux dimensions de la syntaxe, mais que vous voulez l'adresse de cinq mémoire de l'emplacement de départ àzippi
avec une dimensions de la syntaxe.zippo
est une autre chose tout à fait. Il contient l'adresse d'un bloc de mémoire assez grande pour contenir deux pointeur, et si vous faites eux point à certains tableaux d'entiers, vous pouvez déréférencement avec le tableau à deux dimensions de la syntaxe d'accès.Très bien expliqué par le Roseau, je vais ajouter quelques points de plus pour faire plus simple, lorsque nous nous référons à
zippo
ouzippo[0]
ouzippo[0][0]
, nous sommes toujours en se référant à la même adresse de base du tableauzippo
. La raison étant que les tableaux sont toujours bloc contigu de mémoire et les tableaux multidimensionnels sont multiples seule dimension des tableaux en permanence placé.Lorsque vous avez à incrémenter chaque ligne, vous avez besoin d'un pointeur
int *p = &zippo[0][0]
, et de fairep++
incrémente le pointeur par chaque ligne.Dans votre exemple, l'id de son 4 X 2 tableau, faire des
p++
son, pointeur pointe actuellement à la deuxième série de 4 éléments.