3 votes

Pourquoi l'attribution d'un grand nombre en un seul octet fonctionne-t-elle en C ?

int *ptr = malloc(sizeof(char));

*ptr = 100000;

printf("%d\n", *ptr); // 100000

Cela ne devrait-il pas permettre d'allouer suffisamment de mémoire pour un char c'est-à-dire 1 octet ? Par conséquent, le plus grand nombre ne devrait-il pas être 255 ?

Comment l'impression se poursuit-elle ? 100000 ?

Mise à jour

Merci pour vos réponses. S'il écrase les octets suivants, comment le C peut-il savoir que ce nombre est plus grand qu'un octet, et ne pas se contenter de regarder dans le premier octet ?

11voto

tcrosley Points 729

En effet, le langage C ne permet pas de vérifier l'étendue de la mémoire. Il alloue un octet, puis votre affectation via le pointeur l'écrase ainsi que les trois octets suivants. Si vous aviez alloué un autre bit de mémoire juste après le premier malloc, mais avant l'affectation, vous auriez pu écraser une partie du tas (en fonction de la façon dont votre malloc fonctionne).

C'est pourquoi les pointeurs peuvent être très dangereux en C.

Le %d dans l'instruction de format (plus le type de la variable) indique au compilateur qu'il s'agit d'un int et qu'il accède aux quatre octets.

Notez que si vous aviez réellement assigné la valeur à un char, par exemple char *ptr ; *ptr = 100000 ;

alors avec certains compilateurs (et en supposant que les caractères simples soient traités comme signés par défaut), il aurait été imprimé -96, et non 255 (ou 127). C'est parce que le compilateur ne limite pas automatiquement la valeur à la valeur la plus élevée possible (127 dans un caractère signé, 255 dans un caractère non signé), mais au lieu de cela, il déborde. La plupart des compilateurs se plaindront que vous essayez d'assigner une valeur constante qui dépasse la variable.

La raison pour laquelle il s'agit de -96 est que 100000 % 256 est égal à 160, mais en tant que caractère signé, il est restitué sous la forme -(256-160).

5voto

Jon Purdy Points 19408

Réponse courte : vous invoquez un comportement non défini en écrivant dans une mémoire qui ne vous appartient pas, et vous ne savez donc jamais ce que vous pouvez obtenir. Cela peut juste fonctionner, cela peut planter, ou cela peut faire un certain nombre d'autres choses. Dans ce cas, vous mettez un int à l'endroit où ptr qui écrit le premier octet de la référence int dans la région allouée d'un octet, et écrase tout ce qui se trouve dans les trois octets suivants.

Lorsque vous relisez la valeur à l'aide de la touche %d spécificateur de format, printf lit sizeof(int) d'octets de la mémoire pour les imprimer sous la forme d'un int . Si vous souhaitez obtenir la valeur d'un seul octet, vous devez procéder de la manière suivante :

printf("%d\n", *(char*)ptr);

En d'autres termes, il s'agit d'indiquer au compilateur que ptr se réfère à un char , puis de l'obtenir char qui est promue au rang de int dans une liste d'arguments et qui est ensuite restituée correctement par le programme %d spécificateur.

3voto

Svisstack Points 9001

Il s'agit d'un débordement de 3 octets. Un débordement comme celui du logo stackoverflow, mais sur un tas et non une pile.

2voto

Mehrdad Afshari Points 204872

La réponse la plus simple est la suivante : il n'y a aucune garantie de réussite.

En fait, vous corrompez la mémoire autour du pointeur.

1voto

Bill Forster Points 3298

Pour répondre à votre nouvelle question, C "voit" *ptr, c'est-à-dire le contenu de ptr lorsque ptr pointe vers un entier. Il lit donc un entier à partir de ce ptr. Il a déjà oublié que vous n'avez alloué qu'un seul caractère. Les deux parties (allocation et accès) ne sont pas liées par ce que vous avez exprimé dans votre code.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X