Maison > Questions et réponses > le corps du texte
C语言指针问题 下面代码为什么第二个数字是5呢?
int a[5] = {1,2,3,4,5};
int *p = (int *)(&a+1);
NSLog(@"%d,%d", *(a+1), *(p-1));
阿神2017-04-21 11:19:34
&a donne un pointeur vers le tableau, donc &a+1 se déplace en fait en fonction de la longueur du tableau. Si vous souhaitez simplement obtenir le deuxième élément du tableau, utilisez *(&a[0]+1), car le type de données de &a[0] est int*. Dessinez d’abord une image :
Supposons que nous ayons le tableau suivant
int a[5] = {1,2,3,4,5};
int *x = &a+1;
Bien que le programme ci-dessus puisse être compilé et transmis, le compilateur émettra un avertissement car les types de x et a ne correspondent pas. Il existe deux façons de supprimer l'avertissement
.1. Par conversion de type forcée
int *x = (int *)(&a+1);
print("%d\n",*(x-1));
2. Trouvez un type approprié pour cela. Le type de &a est int (*)[5]
int (*x)[5] = &a+1;
printf("%d\n",**(x-1));
Cela implique comment écrire les types de données appropriés, ce qui est très important dans l'affectation et le passage des paramètres !
Donc, je dois d'abord résumer les types de données de a, &a et &a[0]
a est le nom du tableau, qui est le pointeur vers le premier élément du tableau Il ne fait aucun doute qu'ici, le type de données du premier élément du tableau est int, donc. le type de données de a est int*.
int(*)[5 ] .
int*.
Regardez d'abord la partie du code qui réussit la conversion de type forcée. Quel nombre va-t-il afficher ?
La réponse est 5 ! D'après le résumé des types de données de tout à l'heure, nous pouvons savoir que le type de données de &a est
int (*)[5], donc &a+1 a en fait été déplacé de 5*sizeof(int) octets Maintenant, le pointeur pointe vers l'élément après le dernier élément du tableau (Figure 1), c'est-à-dire qu'il a franchi la frontière ! Mais parce que le type de données de x est en fait int * Donc pour x-1, il est en fait déplacé de 1*sizeof(int) octets vers la gauche, ce qui signifie qu'il pointe vers le dernier élément, donc *(x-1) est obtenu La valeur est le dernier élément du tableau : 5
D'accord, regardons maintenant la deuxième partie. Quel nombre cela produira-t-il ? Ne parlons pas d’abord de la réponse. Je viens de le dire ici. Le type de données de Sizeof(int)*5 octets sont déplacés en unités, donc x-1 est en fait déplacé vers la gauche de sizeof(int)*5 octets. Il est déplacé sur ma machine. 20 octets, ce qui revient au premier élément du tableau, donc la réponse est : 1Ce qui précède est un tableau à une dimension. Maintenant, je veux parler de la situation d'un tableau à deux dimensions. Il y a le morceau de code suivant :
int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
/*
?? = a; // int (*b)[3] = a;
?? = a[0]; // int *c = a[0];
?? = a[0][0] // int d = a[0][0];
?? = &a; // int (*e)[3][3] = &a;
?? &a[0]; // int (*f)[3] = &a[0]
?? &a[0][0]; // int *g = &a[0][0]
*/
Examinons d'abord les types de données de a, a[0], &a, &a[0], &a[0][0] :
Faites attention au texte en gras ci-dessus. Le nom du tableau est un pointeur vers le premier élément du tableau !
Quel est le type de données d'un ? ? int * ? Non, le cœur de ce texte en gras sont les cinq mots le premier élément. Le premier élément de a n'est-il pas simplement a[0][0] ? À proprement parler, non, le premier élément de a est en fait a[0], alors quel est le type de données de a[0] ? un[0] est un tableau contenant trois éléments int, donc le type de a[0] est le même que le type de t dans int t[3], qui est int* Depuis le type de données du premier élément. est int*, si ce tableau à deux dimensions est considéré comme un tableau à une dimension, il s'agit en fait d'un tableau contenant trois éléments int*. Un tableau est un tableau de pointeurs, donc le type de données de a est int (*)[3]
Regardons à nouveau &a. Comme mentionné en parlant de tableaux unidimensionnels, l'adresse obtenue en prenant l'adresse d'un nom de tableau est un pointeur vers le tableau, donc le type de données de &a est int (*)[3] [3]
&a[0] Cela semble un peu pénible, mais comme mentionné dans le paragraphe précédent, a[0] est un tableau contenant trois éléments int, et int t[3] Le type de données de t est le même, qui est int* Naturellement, le type de données de &a[0] est le même que le type de données de &t, c'est-à-dire int (*) [3]
À ce stade, nous avons presque écrit sur le type de données dans le tableau bidimensionnel. Maintenant que nous connaissons le type de données, nous pouvons savoir avec précision où le pointeur se déplacera après le calcul !
Regardez le code suivant :
int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
int (*x)[3] = a;
int *k = a[0];
int (*y)[3][3] = &a;
int (*q)[3] = &a[0];
int *z = &a[0][0];
printf("%d\n",(*(x+1))[0]);
printf("%d\n",*(k+1));
printf("%d\n",(*(*(y+1)))[0]);
printf("%d\n",(*(q+1))[0]);
printf("%d\n",*(z+1));
int *p = (int *)(y+1);
printf("%d\n",*(p-1));
x est int (*)[3], donc x+1 est en fait déplacé de 3*sizeof(int) octets, comme le montre la figure :
k est int *, donc k+1 est en fait déplacé de sizeof(int) octets.
y est int (*)[3][3], donc y+1 est en fait déplacé de 3*3*sizeof(int) octets, ce qui correspond au dernier du tableau L'élément après l'élément. Comme le montre l'image :
q est int (*)[3], donc q+1 est en fait déplacé de 3*sizeof(int) octets.
z est int *, donc z+1 est en fait déplacé de sizeof(int) octets.
Ainsi, lors de l'ajout et de la soustraction de pointeurs de tableau, la chose la plus importante est de connaître la taille de son pas, et la taille du pas est déterminée par le type de données !
PHP中文网2017-04-21 11:19:34
La personne qui a répondu au premier étage a très bien écrit, veuillez développer
La valeur du pointeur est l'adresse d'un tableau
int (* pa)[5];
pa++;pa recule de 20 octets (5*4)
Contraste, les éléments du tableau sont des pointeurs (int*)
int *pa[5];
pa++;pa recule de 4 octets
高洛峰2017-04-21 11:19:34
Désolé de reposter un ancien message. J'ai vu cela accidentellement, car dans le passé, lorsque je faisais de la programmation embarquée, des tableaux et des pointeurs étaient souvent utilisés, y compris l'attribution directe d'une adresse mémoire à la variable de pointeur (cela n'est généralement pas utilisé dans les applications normales), et je n'avais jamais trouvé &arr avant. Quelle est la différence avec arr. J'ai vérifié spécifiquement aujourd'hui et découvert que cela dépend du compilateur. Certains compilateurs traitent les tableaux et les pointeurs séparément. La signification de prendre une adresse pour un nom de tableau concerne la mémoire entière du tableau. Certains compilateurs considèrent le tableau comme une forme spécifique de pointeur. Dans ce cas, le pointeur saute d'un point. élément de mémoire du tableau, mais la mémoire du tableau entière n'existe pas.