Lorsque l'on a besoin de mémoriser des informations au cours de l'exécution d'un programme, on peut demander à réserver une partie de la mémoire. Le plus simple pour ce faire est de déclarer une variable.
int n = 12;Cette déclaration est une instruction qui doit toujours être placée au début d'un bloc (immédiatement après une accolade ouvrante).
Le premier mot de la déclaration est le type de la variable. Nous avons déjà vu les types int, char et double. Cette information sert à la fois à savoir combien de mémoire réserver (un octet pour un char, quatre pour un int, etc) et aussi à se souvenir comment interpréter le contenu de la mémoire (chaque type obeit à un standard de représentation).
Le deuxième mot est un identificateur, c'est à dire le nom de la variable. Vous pouvez choisir n'importe quel nom, pourvu que vous respectiez quelques règles :
Le symbole = suivi d'une expression sert à initialiser la variable. Cela permet de décider du contenu de la variable lors de sa réservation. Cette partie de la déclaration est optionnelle, mais fortement recommandée : si vous l'omettez, la variable aura une valeur inconnue (pouvant parfois même varier d'une exécution à l'autre).
Lorsque vous avez besoin de plusieurs variables du même type, vous pouvez les déclarer en une seule instruction.
double x = 12.5, y = -0.54, z = 1.4e-3;
Durant l'exécution d'un programme, les valeurs stockées dans les variables sont susceptibles de changer. Le plus souvent, ce changement est effectué par le biais d'une affectation.
int main(void) { int n = 12; printf("%d\n", n); n = 15; printf("%d\n", n); return EXIT_SUCCESS; }Ce programme affichera 12 puis 15. La valeur de n a changé en cours d'exécution.
Le symbole =, qui sert aussi à désigner l'initialisation, indique ici une affectation. Dans la partie gauche on trouve obligatoirement le nom de la variable à modifier, et dans la partie droite on trouve une expression dont le résultat fournira la valeur à placer dans la variable.
Remarque Une affectation ressemble souvant à une équation, mais c'est un piège. Considérez l'instruction suivante :
n = n+1;Mathématiquement, une telle équation est insoluble. Mais en tant qu'affectation, c'est parfaitement raisonnable. On comprend que nous tirons de la mémoire la valeur de n, puis on lui ajoute 1, et enfin on remet le résultat dans la mémoire là où se trouve n.
Les réels sont le plus souvent manipulés en les représentant par des données de type double.
Une valeur de type double est stockée sur 64 bits, soient 8 octets. L'encodage en binaire d'une telle valeur obeit au format «nombre en virgule flottante à double précision» conformément au standard IEEE 754. 1 bit sert à indiquer le signe, 11 bits servent à donner un exposant qui permet de placer la virgule (c'est pour cela qu'elle est flottante), et enfin 52 bits servent à connaître les chiffres (binaires) qui forment la valeur.
Une constante de type double est identifiée dans un fichier source par la présence d'une virgule (sauf que le langage C respecte l'usage anglo-saxon qui préconise un point au lieu d'une virgule).
printf("%f", -254.87);Remarque Le signe peut être omis lorsqu'il est positif, mais il ne faut jamais oublier le point.
Alternativement, on peut exprimer la même valeur en notation scientifique :
printf("%f", -2.5487e2);printf affiche un double en notation simple si on lui donne le format "%f", en notation scientifique avec le format "%e", ou il choisit la notation la plus courte parmi les deux précédentes si on lui donne "%g".
Remarque Par défaut, printf affiche toujours six chiffres après la virgule. C'est généralement trop, donc on ajoute souvent un modificateur au format pour forcer le nombre de chiffres.
printf("%.2f", -0.157);Cet exemple affiche :
-0.16
Même si ça ne correspond pas aux mêmes circuits dans le processeur, les double peuvent être additionnés, soustraits, multipliés ou divisés entre eux avec la même notation que pour les entiers. Par contre, il n'y a pas d'opérateur bit-à-bit fonctionnant avec des double.
Nous avons vu précédemment la fonction getchar qui sert à lire des caractères à la console. Lorsque le texte tapé par l'utilisateur du programme forme un entier ou un réel, on peut lire un par un tous les caractères concernés, puis les interpréter pour former la valeur correspondante en mémoire. C'est assez fastidieux.
Il existe dans la bibliothèque standard (et dans stdio.h
) une fonction qui
fait exactement cela à notre place pour nous faire gagner du temps : c'est
scanf.
int main(void) { int n; double x; printf("Entrez un réel : "); n = scanf("%lf", &x); printf("son carré vaut : %f\n", x*x); return EXIT_SUCCESS; }
On peut constater trois détails importants :
Le résultat de scanf indique si la lecture s'est bien passée. Il vaut :
Tout comme getchar, scanf pioche dans le tampon, et provoque une interruption momentanée du programme si le tampon est vide (jusqu'à ce que l'utilisateur le remplisse).
Remarque On dit parfois que scanf est glouton : si vous lui demandez de lire un entier et que l'utilisateur tape 12mn, scanf pourrait s'arrêter au premier caractère et consider qu'il a lu l'entier 1, mais il préferera aller le plus loin possible et donner plutôt l'entier 12. Il n'ira pas jusqu'à l'indigestion : le caractère d'après n'est pas un chiffre et il laissera donc tout ce qui suit dans le tampon.
Poussières. Testez ce programme :
int main(void) { printf("%f\n", 12345.678910111213); return EXIT_SUCCESS; }Vous ne devriez pas être surpris par le résultat. Modifiez le format du printf pour qu'il affiche 12 chiffres après la virgule. Êtes-vous satisfaits du résultat ? Affichez maintenant 15 chiffres. Qu'avez-vous appris ?
Opérations. Trouvez où est l'erreur dans le programme suivant :
int main(void) { printf("%f\n", 5.0+2.5); printf("%f\n", 5.0-2.5); printf("%f\n", 5.0*2.5); printf("%f\n", 5.0/2.5); printf("%f\n", 5.0%2.5); return EXIT_SUCCESS; }
Extrémités. Vous serez peut-être surpris de constater que ce programme, qui ne veut rien dire, est pourtant parfaitement fonctionnel. Pouvez-vous expliquer les résultats obtenus ?
int main(void) { printf("%f\n", +1.0/0.0); printf("%f\n", -1.0/0.0); printf("%f\n", -0.0/0.0); return EXIT_SUCCESS; }
Téléscopage. Écrivez un programme qui :
Intérêts. Un produit financier promet de rapporter 4% par an, mais l'argent investi ne peut être retiré qu'au bout de 7 ans. Écrivez un programme qui demande à l'utilisateur combien d'euros il souhaite investir dans son épargne, puis affiche le montant de l'épargne après chaque année écoulée, jusqu'à la date de fin de contrat.
Remarque Lorsque l'on affiche une colonne de nombres, il est d'usage d'aligner verticalement les unités. Ce n'est malheureusement pas ce que nous obtiendrons avec un printf normal. Rajoutons une option de format :
printf("%9.4f", 10.25);L'option .4 à l'intérieur du %f indique que nous souhaitons voir 4 chiffres après la virgule. L'option 9 indique que tout l'affichage doit faire au moins 9 caractères (en comptant tous les chiffres, la virgule, et l'exposant le cas échéant). printf rajoutera des espaces au début pour rallonger si nécessaire. On aurait aussi pu écrire 09 pour qu'il rajoute des 0 au lieu d'espaces, ou -9 pour qu'il rajoute des espaces à la fin.
Somme. Écrivez un programme qui demande à l'utilisateur de lui donner cinq nombres réels, puis en affiche la somme. Lorsque vous serez satisfaits de votre programme, modifiez-le pour qu'il fasse la même chose, mais en employant seulement deux variables de type double.