Maths, Informatique, Jeux
Site Web réalisé par Frédéric et François WANG
Répertoire principalInformatiqueProgrammationCodes sourceBoguesBogues en C

Introduction

Les codes sources C présentés ne comportent pas d'erreurs qui les empêchent d'être compilé (tel que l'oubli d'un point-virgule par exemple). Je n'indiquerai pas non plus les include pour éviter de surcharger le code source.

Pour chaque bogue, vous trouverez dans l'ordre une présentation, le code source, et enfin l'explication de l'erreur. En plus de ça, avant de donner une explication, je vous propose un petit jeu sous forme de questionnaire, histoire de voir si vous avez trouvée l'erreur. A vous de jouer !

Affichage sans limite d'entiers limités

Présentation

On désire faire afficher les valeurs que peut prendre un entier positif codé sur 8 bits (unsigned char). par l'ordinateur, c'est-à-dire 28 = 256 valeurs différentes qui sont 0, 1, 2... 254, 255.

Pour cela, on utilise la boucle for(n=0;n<256;n++) qui initialise n à 0, l'augmente à chaque passage de 1, et l'arrête lorsque cette valeur n'est plus en dessous de 256. La fonction printf se charge d'afficher chacune des valeurs que prends n.

Code source

int main()
{
unsigned char n;
for(n=0;n<256;n++)printf("%d\n",n);
}
A quel endroit faut-il changer le code source si on veut éviter un bogue ?
Dans la déclaration de n.
Dans la structure de la boucle.
Dans la syntaxe de printf().

Explication du bogue

A l'exécution, le programme affiche comme prévu les nombres de 0 à 255, mais une fois arrivée à 255, il recommence à zéro ! En effet, comme dit dans la présentation, le type unsigned char prends les valeurs entières allant de 0 à 255... il ne peut donc pas dépasser 255, ce qui empêche la boucle de s'arrêter ! On constate que lorsque n vaut 255 et que l'on fait n++, n prends alors la valeur 0 : la boucle recommence.

Cette erreur ne vient certainement pas de la fonction printf() et même en changeant la structure de la boucle - tel que for(n=0;n<=255;n++) ou for(n=0;n!=0;n++) - on ne peut éviter le bogue sans passer par une autre variable que n... ou sans changer son type. Il faut donc la déclarer autrement, comme un unsigned short par exemple.

En résumé, si il faut bien choisir son type de variable en fonction de son utilisation (un int codé sur 4 octets peut prendre 4 294 967 296 valeurs différentes alors qu'un char codé sur 1 octet en prends 256, il est donc inutile de gaspiller 3 octets pour des variables prenant simplement quelques valeurs différentes), il faut faire attention quand on approche des valeurs limites ! En effet, le bogue nous a enseigné qu'en se servant d'une unique variable dans une boucle et en voulant lui faire prendre toutes ses valeurs, la boucle ne peut savoir quand s'arrêter !

Affichage répété d'une chaîne

Présentation

La fonction Exclamer(texte, n_exclamation) se charge d'afficher du texte, en y ajoutant, via la fonction strcat, n_exclamation points d'exclamation, et en revenant à la ligne. La fonction principale, se compose d'une boucle où la variable n prends les valeurs 1, 2, 3. A chaque fois, on appelle la fonction Exclamer avec pour paramètre la chaîne "Bonjour" et le nombre n, de sorte que le programme affiche trois lignes de "Bonjour" comportant 1, 2 puis 3 points d'exclamation :

Bonjour !
Bonjour !!
Bonjour !!!

Code source

void Exclamer(unsigned char *texte,unsigned char n_exclamation)
{
for(;n_exclamation>0;n_exclamation--)strcat(texte,"!");
printf("%s\n",texte);
}

int main()
{
unsigned char n;
for(n=1;n<=3;n++)Exclamer("Bonjour ",n);
}
Quelles erreurs peut-on craindre ?
La boucle for(n=1;...) ne va pas s'arrêter.
Le texte ne va pas s'afficher comme on le souhaite.
La fonction Exclamer() ne revient pas à la ligne.
La fonction Exclamer() n'affiche pas assez de points d'exclamation
Un changement d'octets dans une zone de mémoire non réservée.
La boucle for(;n_exclamation>0...) ne va pas s'arrêter.

Explication du bogue

Les structures des 2 boucles sont correctes, et en particulier, celle qui se trouve dans la fonction Exclamer() ajoute bien le nombre de points d'exclamation qu'on lui donne. De plus, le retour à la ligne assuré par le caractère '\n'. Cependant, le texte ne peut pas pour autant s'afficher comme on le souhaiterait, et d'ailleurs une erreur due à l'écriture sur un emplacement de la mémoire réservée risque de se produire !

Cela nécessite une petite précision... Lorsque l'on se sert de la constante chaîne "Bonjour", une zone en mémoire est réservée pour retenir cette chaîne. La première fois que l'on appelle la fonction Exclamer() en passant le pointeur sur l'emplacement où est stockée la chaîne, la fonction strcat() y ajoute alors un point d'exclamation et printf() affiche la chaîne "Bonjour !" voulue. Mais quand on l'appelle pour la deuxième fois, en passant toujours le même pointeur, la chaîne pointée est "Bonjour !" et strcat(), en ajoutant 2 points d'exclamations la transforme en "Bonjour !!!", soit un point d'exclamation en trop. La troisième fois, la fonction Exclamer() ajoute 3 points d'exclamation de plus et par conséquent affiche "Bonjour !!!!!!".

Quant à la deuxième erreur, elle provient du fait que cas envisagé est celui où les octets qui suivent la zone réservée par la chaîne "Bonjour" ne sont pas eux-même réservés. En effet, si ce n'étaient pas le cas, lorsque l'on rajoute des points d'exclamations à la chaîne en dehors de la zone réservée, on écrit alors sur d'autres zones déjà utilisées, et on risque de provoquer des erreurs...

On retiendra de ces bogues qu'il faut faire attention quand on utilise des « constantes chaînes de caractères » car elles sont retenues en mémoire comme des variables globales (notons au passage qu'il vaut donc mieux utiliser des fichiers pour retenir de longs textes), et par conséquent ne sont donc pas vraiment constante puisque l'on peut les modifier via un pointeur.

Cette page est conforme aux normes du W3C - Auteur : Frédéric WANG - Dernière mise à jour : mercredi 4 août 2004
Valid XHTML 1.1 Valid MathML 2.0 Valid SVG Valid CSS Amaya, the W3C browser/editor Déclaration qualité Opquast Firefox