11
votes

Conversion d'adresse d'un tableau à d'autres types de données

 1
 210 
 42
 210

6 commentaires

Astuce: 6 * 7 = 42 , 5 * 7 * 6 = 210


@Armin pouvez-vous s'il vous plaît expliquer?


Un autre indice - vous ne convertissez pas l'adresse en un type différent jusqu'à ce que après vous avez déjà fait l'arithmétique sur les pointeurs, qui est fait en supposant le type d'origine, pas le type final ...


@Twalberg pour quel exemple serait-ce vrai, sûrement pas pour les trois derniers.


@Armin Ceci est vrai de tous les trois derniers exemples ci-dessus, en raison des règles de préséance de l'opérateur - (char *) (& ar + 1) Par exemple, sait que arrondi est un char [5] [7] [6] , ce qui signifie que & arr + 1 est arr + 5 * 7 * 6 ou < code> arr + 210 , qui est ensuite coulé sur un char * - (char *) (arr) + 1 serait le moyen de convertir ARR à un Char * Avant que l'arithmétique est terminé.


@Twalberg Tu as raison. Je regardais quelque chose d'autre et complètement sans importance.


3 Réponses :


6
votes

Eh bien, si je voulais diviser les cheveux: En premier lieu, le code invoque un comportement indéfini sur la place, tout au long des déclarations printf () . La différence de deux pointeurs a type ptrdiff_t , et pour cela, le spécificateur de conversion correct est % TD , pas % d . .

Le reste n'est que la spéculation. Supposons que votre système soit raisonnable et numériquement la valeur du pointeur & arr est toujours identique, quel que soit le type à convertir.

MAINTENANT, (& Ar + 1) - & ARR est 1, bien sûr, selon les règles du pointeur arithmétique. (La différence réelle entre les deux pointeurs est 210 * Tailleofof (int) octets, mais ce n'est pas des mathématiques de l'école, mais du pointeur arithmétique, c'est pourquoi le résultat est donné en unités de taille Taillef (t ) , où t est le type de base du pointeur.)

puis (char *) (& ar + 1) - (char *) & ar jette les pointeurs sur char * , et depuis la taille de Char < / Code> est 1, cela imprimera la différence en octets; Vous avez un trompeur / abusif de pointeur arithmétique ici.

En outre: printf ("% d \ n", (non signé) (ARR + 1) - (non signé) Ar) soustrait deux pointeurs de type int (*) [7) [7) [ ] [6] . C'est ce que arrondi se désintègre. Bien sûr, 7 * 6 = 42, donc la différence de taille entre arr + 1 et arr est de 42 éléments.

p , cependant, ce n'est pas un pointeur sur le premier élément de la matrice, mais c'est un pointeur sur le tableau lui-même. Son type est correctement désigné comme int (*) [5] [6] [7] . Maintenant, si vous imprimez la différence en utilisant ce type, mais vous ne laissez pas le compilateur faire la division en le trompant que les pointeurs sont juste non signé , alors vous obtiendrez 5 * 6 * 7 , qui est 210.


2 commentaires

Celui qui a baissé, laissez un commentaire. Je ne vois aucune raison pour un bowvote.


La réponse est mal écrite et n'explique pas les types impliqués. Ensuite, la réponse est écrite de manière à effectuer de véritables déclarations et à montrer, mais pas à enseigner des concepts à quelqu'un qui ne les comprend pas. En outre, la conversion en Char * et soustraire ne résout pas ou abuser du pointeur arithmétique; Il est entièrement défini par la norme C.



5
votes

in (& arr + 1) - & arr :

& ar est l'adresse d'un tableau de 5 tableaux de 7 tableaux de 6 Char . L'ajout d'un produit produit l'adresse de l'endroit où le tableau NEXT de 5 tableaux de 7 tableaux de 6 Char serait, si nous avions un tableau de ces objets au lieu d'un seul. Soustrayez l'adresse d'origine, & ARR , produit la différence entre les deux adresses. Pour la norme C, cette différence est exprimée en tant que nombre d'éléments entre les deux adresses, où le type d'élément est le type d'objet pointé sur. Étant donné que ce type est un tableau de 5 tableaux de 6 tableaux de 6 Char , la distance entre les deux adresses est un élément. En d'autres termes, la distance entre & arr vers (& arr + 1) est une matrice de 5 tableaux de 7 tableaux de 6 Char .

dans (char *) (& arr + 1) - (char *) & ar :

& arr + 1 est à nouveau un pointeur sur l'endroit où la prochaine matrice de 5 tableaux de 7 tableaux de 6 Char serait. Lorsqu'il est converti en un char * , le résultat est un pointeur sur quel serait le premier octet de ce prochain tableau. SimpleLLY, (char *) etr est un pointeur sur le premier octet du premier tableau. Ensuite, soustrayez les deux pointeurs génère la différence entre eux dans des éléments. Étant donné que ces pointeurs sont pointus sur char , la différence est produite en tant que numéro de char . La différence est donc le nombre d'octets dans une matrice de 5 tableaux de 7 tableaux de 6 char , qui est 5 • 7 • 6 Char ou 210 Char .

dans (non signé) (arr + 1) - (non signé) Art :

Etant donné que Art n'est pas utilisé avec & (ou Tailleof ou d'autres cas exceptionnels), il est automatiquement converti à partir d'un tableau de 5 tableaux de 7 tableaux de 6 Char à un pointeur sur le premier élément. Ainsi, il s'agit d'un pointeur d'un tableau de 7 tableaux de 6 Char . Ensuite, arr + 1 est un pointeur sur la matrice suivante de 7 tableaux de 6 Char . Lorsque cette adresse est convertie en non signé , le résultat, dans la mise en œuvre de C que vous utilisez, est en effet l'adresse de la mémoire de l'objet. (Ceci est commun mais n'est pas garanti par la norme C et se casse certainement lorsque les adresses sont de 64 bits, mais non signé est de 32 bits.) De même, (non signé) arr compte est l'adresse du premier objet. Lorsque les adresses sont soustraites, le résultat est la distance entre eux en octets. La différence est donc le nombre d'octets dans une matrice de 7 tableaux de 6 Char , qui correspond à 7 • 6 octets, ou 42 octets. Notez la différence de clé dans ce cas: & ar est un pointeur sur une matrice de 5 tableaux de 7 tableaux de 6 Char , mais ARR est un Pointeur sur une matrice de 7 tableaux de 6 Char .

dans (non signé) (p + 1) - (non signé) p :

p est un pointeur sur une matrice de 5 tableaux de 7 tableaux de 6 Char . Ensuite, p + 1 est un pointeur sur l'endroit où le tableau suivant serait. Convertir en non signé actes comme décrit ci-dessus. La soustraction donne la différence d'octets d'octets, de sorte qu'il est de la taille d'un réseau de 5 tableaux de 7 tableaux de 6 char , de sorte que c'est à nouveau 210 octets.

comme un de côté:

Le type de (& arr + 1) - & ar est ptrdiff_t et doit être imprimé avec % TD . .

Le type de (char *) (& arr + 1) - (char *) & ar est ptrdiff_t et doit être imprimé avec % TD .

Le type de (non signé) (arr + 1) - (non signé) Art est non signé INT et doit être imprimé avec % u .

Le type de (non signé) (p + 1) - (non signé) p est non signé INT et doit être imprimé avec % u .


2 commentaires

@Grijeshchauhanhan: Les ajouts, les soustractions et les conversions vers Char * dans ce code sont définis. Les conversions sur non signé ne sont pas complètement définies mais se sont bien comportées dans des implémentations typiques C à condition que les adresses résultantes soient dans les limites du type non signé. L'utilisation de spécificateurs de format incorrects n'est pas défini.


Merci!! Je l'ai eu maintenant, j'ai lu cette section de votre réponse à nouveau (j'ai voté 2e). Mais ma limite de vote de commentaire croisée. Merci



5
votes

Remarque & Art Code> est une adresse complète de tableau de caractères 3 dimensions, alors que Arr code> pointe sur le premier élément de charme 2 dimensions. Quelque chose comme ci-dessous dans le diagramme: xxx pré>

type & arr code> est char (*) [5] [7] [6] code> qui est Adresse de Char 3D-Tableau de dimension [5] [7] [6] code>. Différence de valeur-sage entre & Arr code> et etr + 1 code> est 5 * 7 * 6 * Tailleof (char) code> = 210 code >.
Parce que la taille de Char [5] [7] [6] code> est 5 * 7 * 6 * Taille de (char) code>.
Dans votre code & ARR CODE> Points sur une matrice 3-D et & Arry + 1 Code> Le tableau 3-D suivant (qui n'existe pas dans notre code). P>

Vérifiez ce code de travail chez CODEPADE : P>

 Char         : 1 
 Char[5]      : 6 
 Char[5][7]   : 42 
 Char[5][7][6]: 210 


2 commentaires

Vérifiez ce Diagramme


@Alex Essayez votre code à nouveau avec chaque typecase cette fois: (char (*) [5] [7] [6]) . Par exemple: printf ("% d \ n", ((char (*) [5] [7] [6]) (ARR + 1) - ((Char (*) [7] [7] [ 6]) ARR); et dire la raison de la sortie.