Je venais de lire du code et j'ai constaté que la personne utilisait arr[-2]
Pour accéder au 2e élément avant le arr
, comme ceci:
|a|b|c|d|e|f|g|
^------------ arr[0]
^---------- arr[1]
^---------------- arr[-2]
Est-ce permis?
Je sais que arr[x]
Est identique à *(arr + x)
. Donc arr[-2]
Est *(arr - 2)
, ce qui semble bien. Qu'est-ce que tu penses?
C'est correct. À partir de C99 §6.5.2.1/2:
La définition de l'opérateur en indice [] est que E1 [E2] est identique à (* ((E1) + (E2))).
Il n'y a pas de magie. C'est une équivalence 1-1. Comme toujours lors de la déréférence d'un pointeur (*), vous devez vous assurer qu'il pointe vers une adresse valide.
Ceci n'est valide que si arr
est un pointeur qui pointe vers le deuxième élément d'un tableau ou un élément ultérieur. Sinon, il n'est pas valide, car vous accéderiez à la mémoire en dehors des limites du tableau. Donc, par exemple, ce serait faux:
int arr[10];
int x = arr[-2]; // invalid; out of range
Mais ce serait bien:
int arr[10];
int* p = &arr[2];
int x = p[-2]; // valid: accesses arr[0]
Il est toutefois inhabituel d’utiliser un indice négatif.
Cela me semble bien. Il serait cependant rare que vous en ayez légitimement besoin.
Ce qui était probablement que arr
pointait au milieu du tableau, rendant ainsi arr[-2]
montrant quelque chose dans le tableau d'origine sans sortir du cadre.
Je ne sais pas si cela est fiable, mais je viens de lire la mise en garde suivante à propos des indices de tableaux négatifs sur les systèmes 64 bits (sans doute du type LP64): http://www.devx.com/tips/Tip/41349
L’auteur semble dire que les index de tableau int de 32 bits avec un adressage de 64 bits peuvent donner lieu à des calculs d’adresses erronées à moins que l’indice de tableau ne soit explicitement promu à 64 bits (par exemple, via une conversion ptrdiff_t). J'ai effectivement vu un bogue de sa nature avec la version PowerPC de gcc 4.1.0, mais je ne sais pas s'il s'agit d'un bogue de compilateur (c'est-à-dire qu'il devrait fonctionner selon le standard C99) ou d'un comportement correct (c'est-à-dire que l'index doit être converti en 64 bits pour un comportement correct)?
Pour savoir pourquoi quelqu'un voudrait utiliser des index négatifs, je les ai utilisés dans deux contextes:
Avoir une table de nombres combinatoires qui vous dit peigne [1] [- 1] = 0; vous pouvez toujours vérifier les index avant d'accéder à la table, mais le code est ainsi plus propre et s'exécute plus rapidement.
Mettre un centinel au début d'une table. Par exemple, vous voulez utiliser quelque chose comme
while (x < a[i]) i--;
mais alors vous devriez aussi vérifier que i
est positif.
Solution: faites en sorte que a[-1]
est -DBLE_MAX
, pour que x<a[-1]
sera toujours faux.
Je sais que la question a reçu une réponse, mais je n'ai pas pu m'empêcher de partager cette explication.
Je me souviens des principes de la conception du compilateur. Supposons que a soit un tableau int et que la taille de int soit 2, et que l’adresse de base pour a soit 1000.
Comment a[5]
fonctionnera ->
Base Address of your Array a + (index of array *size of(data type for array a))
Base Address of your Array a + (5*size of(data type for array a))
i.e. 1000 + (5*2) = 1010
Cette explication est également la raison pour laquelle les index négatifs dans les tableaux fonctionnent en C.
c'est-à-dire si j'accède à a[-5]
ça va me donner
Base Address of your Array a + (index of array *size of(data type for array a))
Base Address of your Array a + (-5 * size of(data type for array a))
i.e. 1000 + (-5*2) = 990
Il me retournera objet à l'emplacement 990. Par cette logique, nous pouvons accéder aux index négatifs dans Array en C.