Réels

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 :

  • les seuls caractères autorisés sont les chiffres, les lettres, et _.
  • le nom ne doit pas commencer par un chiffre.
  • par convention, les majuscules sont réservées aux noms de constantes.
  • par convention, les noms commencant par _ sont réservés aux bibliothèques standard.
Assurez-vous de choisir un nom parlant, qui permette de communiquer le rôle de l'information représentée.

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 :

  • comme getchar, la fonction scanf produit un résultat que l'on peut placer dans une variable (ici n) à l'aide d'une affectation. Ce résultat est de type int, ce qui explique le type choisi pour n.
  • le premier argument de scanf est un format qui ressemble énormément aux formats employés pour printf ("%d", "%o" ou "%x" pour les int, "%c" pour les char), sauf pour les double qui utilisent le format "%lf".
  • le deuxième argument de scanf est nécessairement le nom d'une variable précédé du symbole &. Le type de cette variable doit correspondre au format demandé.

Le résultat de scanf indique si la lecture s'est bien passée. Il vaut :

  • -1 si la console n'est pas disponible (ça ne devrait jamais arriver).
  • 0 si l'information lue n'est pas au bon format.
  • 1 en cas de succès, et la valeur lue est alors placée dans la variable donnée en argument.

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.

  1. 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 ?

  2. 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;
    }

  3. 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;
    }

  4. Téléscopage. Écrivez un programme qui :

    • demande à l'utilisateur de saisir un réel,
    • affiche ce réel en notation scientifique,
    • demande à l'utilisateur de saisir un caractère,
    • affiche le caractère en question cinq fois de suite.
    Remarque La solution «naïve» donne un résultat surprenant. Déterminez-en la raison et adaptez votre programme en conséquence.

  5. 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.

  6. 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.

retour à la page d'accueil

retour au sommet