J'ai rencontré une expérience étrange en programmation C. Considérez ce code:
int main(){
int array1[6] = {0, 1, 2, 3, 4, 5};
int array2[6] = {6, 7, 8, 9, 10, 11};
printf("%d\n", array1[-1]);
return 0;
}
Lorsque je compile et exécute ceci, je ne reçois aucune erreur ni avertissement. Comme l'a dit mon conférencier, l'index du tableau -1
accède à une autre variable. Je suis toujours confus, pourquoi diable un langage de programmation a-t-il cette capacité? Je veux dire, pourquoi autoriser les indices de tableau négatifs?
programming-languages
arrays
c
Mohammed Fawzan
la source
la source
-1
d'un sous-tableau est un moyen parfaitement valide de faire référence à l'élément avant ce tableau dans le tableau le plus grand. L'autre est que si l'index n'est pas valide, le programme n'est pas valide, mais dans la plupart des implémentations, vous obtiendrez un mauvais comportement silencieux, pas une erreur hors plage.Réponses:
L'opération d'indexation de tableau
a[i]
tire sa signification des caractéristiques suivantes de CLa syntaxe
a[i]
est équivalente à*(a + i)
. Ainsi, il est valable de dire5[a]
d'arriver au 5ème élément dea
.Le pointeur-arithmétique dit que, étant donné un pointeur
p
et un entieri
,p + i
le pointeurp
avancé pari * sizeof(*p)
octetsLe nom d'un tableau
a
devient très rapidement un pointeur vers le 0ème élément dea
En effet, l'indexation de tableaux est un cas particulier d'indexation de pointeurs. Puisqu'un pointeur peut pointer vers n'importe quel endroit à l'intérieur d'un tableau, toute expression arbitraire qui ressemble à
p[-1]
n'est pas fausse par examen, et donc les compilateurs ne considèrent pas (ne peuvent pas) toutes ces expressions comme des erreurs.Votre exemple
a[-1]
oùa
est en fait le nom d'un tableau n'est pas valide. IIRC, il n'est pas défini s'il y a une valeur de pointeur significative comme résultat de l'expressiona - 1
où l'a
on sait être un pointeur vers le 0ème élément d'un tableau. Ainsi, un compilateur intelligent pourrait détecter cela et le signaler comme une erreur. D'autres compilateurs peuvent toujours être conformes tout en vous permettant de vous tirer une balle dans le pied en vous donnant un pointeur sur un emplacement de pile aléatoire.La réponse informatique est:
En C, l'
[]
opérateur est défini sur des pointeurs, pas sur des tableaux. En particulier, il est défini en termes d'arithmétique du pointeur et de déréférence du pointeur.En C, un pointeur est abstraitement un tuple
(start, length, offset)
à la condition que0 <= offset <= length
. L'arithmétique du pointeur est essentiellement une arithmétique levée sur le décalage, avec la mise en garde que si le résultat de l'opération viole la condition du pointeur, il s'agit d'une valeur indéfinie. Déréférencer un pointeur ajoute une contrainte supplémentaire à celaoffset < length
.C a une notion
undefined behaviour
qui permet à un compilateur de représenter concrètement ce tuple sous la forme d'un nombre unique, et de ne détecter aucune violation de la condition du pointeur. Tout programme qui satisfait la sémantique abstraite sera en sécurité avec la sémantique concrète (avec perte). Tout ce qui viole la sémantique abstraite peut être, sans commentaire, accepté par le compilateur et il peut faire tout ce qu'il veut en faire.la source
Les tableaux sont simplement présentés comme des morceaux de mémoire contigus. Un accès à un tableau tel qu'un [i] est converti en un accès à l' adresse d' emplacement de mémoire Of (a) + i. Ce code
a[-1]
est parfaitement compréhensible, il se réfère simplement à l'adresse avant le début du tableau.Cela peut sembler fou, mais il y a plusieurs raisons pour lesquelles cela est autorisé:
a[-1]
est valide. Par exemple, si je sais que cea
n'est pas réellement le début du tableau, mais un pointeur au milieu du tableau, ila[-1]
obtient simplement l'élément du tableau qui se trouve à gauche du pointeur.la source
a[-1]
est parfaitement logique pour certains casa
, dans ce cas particulier, il est tout simplement illégal (mais pas capturé par le compilateur)Comme les autres réponses l'expliquent, il s'agit d' un comportement indéfini en C. Considérez que C a été défini (et est principalement utilisé) comme un "assembleur de haut niveau". Les utilisateurs de C l'apprécient pour sa vitesse sans compromis, et la vérification des choses à l'exécution est (principalement) hors de question pour des raisons de performances. Certaines constructions en C qui semblent absurdes pour les personnes venant d'autres langages ont un sens parfait en C, comme ceci
a[-1]
. Oui, cela n'a pas toujours de sens (la source
On peut utiliser une telle fonctionnalité pour écrire des méthodes d'allocation de mémoire qui accèdent directement à la mémoire. Une telle utilisation consiste à vérifier le bloc de mémoire précédent à l'aide d'un index de tableau négatif pour déterminer si les deux blocs peuvent être fusionnés. J'ai utilisé cette fonctionnalité lorsque je développe un gestionnaire de mémoire non volatile.
la source
C n'est pas fortement tapé. Un compilateur C standard ne vérifierait pas les limites du tableau. L'autre chose est qu'un tableau en C n'est rien d'autre qu'un bloc de mémoire contigu et l'indexation commence à 0, donc un index de -1 est l'emplacement de tout motif binaire avant
a[0]
.D'autres langues exploitent les indices négatifs de manière agréable. En Python,
a[-1]
renverra le dernier élément,a[-2]
renverra l'avant-dernier élément et ainsi de suite.la source
int
, donca[-5]
et, plus généralement,int i; ... a[i] = ...;
sont correctement typés. Les erreurs d'index ne sont détectées qu'au moment de l'exécution. Bien sûr, un compilateur intelligent peut détecter certaines violations.En termes simples:
Toutes les variables (y compris les tableaux) en C sont stockées en mémoire. Disons que vous avez 14 octets de "mémoire" et que vous initialisez ce qui suit:
Considérez également la taille d'un entier comme 2 octets. Ensuite, hypothétiquement, dans les 2 premiers octets de mémoire, l'entier a sera enregistré. Dans les 2 octets suivants, l'entier de la première position du tableau sera enregistré (cela signifie tableau [0]).
Ensuite, lorsque vous dites tableau [-1], c'est comme faire référence à l'entier enregistré en mémoire juste avant le tableau [0], qui dans notre hypothèse, est un entier a. En réalité, ce n'est pas exactement la façon dont les variables sont stockées en mémoire.
la source
la source