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 !
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.
int main()
{
unsigned char n;
for(n=0;n<256;n++)printf("%d\n",n);
}
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 !
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 !!!
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);
}
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.