Le programme ne s’est pas bloqué en cas de dépassement de tampon

Je veux lire une chaîne de clavier et stocker dans buf . Je mets un tableau char buf[6] , ce tableau tout au plus peut stocker 5 caractères et \0 .

Ensuite, je tape 123 456 789 il contient 11 caractères et un \0 , le programme peut toujours être exécuté, mais si je tape une chaîne plus longue, 123 456 789 123 456 789 il se bloque au moment de l’exécution. ces deux entrées sont également hors de scope, mais l’une peut fonctionner, l’autre se bloque?

Voici mon code:

 #include  #include  #include  void read_str(); int main(){ read_str(); system("pause"); return 0; } void read_str(){ char buf[6] = {}; scanf("%[^\n]",buf); printf("%d\n",strlen(buf)); printf("%s\n",buf); } 

Ceci est juste un comportement non défini pour écrire en dehors des limites de la mémoire allouée. Cela peut fonctionner maintenant, mais on ne peut pas compter sur lui pour fonctionner. Le projet de norme C99 de l’ annexe J.2 comportement non J.2 indique:

Un indice de tableau est en dehors de la plage, même si un object est apparemment accessible avec l’indice donné (comme dans l’expression lvalue a [1] [7] étant donné la déclaration int a [4] [5]) (6.5.6).

Notez que la section 3.4.3 Comportement non défini qui définit le terme au paragraphe 2 dit ( souligné par moi ):

Le comportement non défini possible peut aller d’ignorer complètement la situation avec des résultats imprévisibles , de se comporter pendant la traduction ou l’exécution du programme d’une manière documentée caractéristique de l’environnement (avec ou sans émission d’un message de diagnostic), en mettant fin à la traduction ou à l’exécution (avec la publication). d’un message de diagnostic).

La vraie raison est probablement que vous écrasez simplement le contenu de votre stack puisque vous êtes dans un appel de fonction et que vous n’obtenez pas réellement la mémoire que vous ne possédez pas avant d’essayer d’écrire des caractères au-delà de la base. de cela. Même si cela ne plante pas, c’est presque toujours mauvais parce que vous écrasez les valeurs que votre programme y a placées pour une raison. Après tout, si vous plantiez toujours à chaque fois que vous écrasiez une mémoire tampon, les erreurs de débordement de la mémoire tampon ne pourraient jamais se produire et nous le soaps.

Par exemple, votre stack est susceptible de croître vers le bas. Lorsque vous appelez une fonction, vous pouvez obtenir des valeurs de registre, une adresse de retour, des valeurs d’argument et d’autres éléments placés dans la stack. Alors, et seulement alors, vos 6 octets pour buf seront alloués. Si tous ces éléments prenaient, disons, 12 octets, vous pourriez alors écrire 18 caractères et ne toucher que la mémoire que vous ne devriez pas modifier, mais que votre processus possède. Étant donné que votre processus en est propriétaire, vous n’obtiendrez pas d’access mémoire illégal ni de crash. Une fois que vous avez dépassé les 18 octets, vous pouvez très bien vous souvenir que votre processus ne l’appartient pas et vous obtiendrez une erreur de segmentation et le jeu sera mis en place.

La raison C est que vous avez juste un comportement indéfini et que des choses étranges se produisent que vous ne devriez même pas essayer de comprendre.