precedent retour  sommaire du cours C++ suivant

Le Langage C++

cours n° 2

Patrick TRAU 13/10/04

Cours n° 2

4) Les variables simples et opérateurs associés

4.1) les types entiers

Nous allons revoir la structure d'un petit programme vue au cours précédent (et évidemment des choses nouvelles), mais présentées dans un sens différent : nous allons partir des données que nous voulons traiter pour construire le programme autour.

Un programme est un peu comme une recette de cuisine. On définit au début tous les ingrédients, plats et récipients nécessaires, puis on explique dans l'ordre exactement comment il faut procéder. J'aime aussi faire le parallèle avec une procédure, telle qu'on le comprend dans l'industrie. Ici aussi, dans un format standardisé, on définit les outils et matières brutes nécessaires, puis on détaille la manière de faire.

L'ordinateur ne sait travailler que sur des nombres en binaire. C'est pourquoi il va falloir tout codifier sous forme numérique : des nombres, mais aussi du texte, des images, du son... Limitons nous pour l'instant aux nombres. Ils seront stockés dans des mémoires de l'ordinateur, chacune définie par un numéro (appelé « adresse »). Mais à quel endroit de l'ordinateur sont placés ces nombres ne nous intéresse pas, c'est pourquoi on préfère laisser au compilateur la tâche de l'adressage des mémoires. Nous allons simplement les désigner par un nom : l'identificateur.

Quand nous aurons besoin d'une mémoire pour stocker une valeur (on nomme cela une variable), il suffit de la déclarer : on dit quel type de variable on désire, et le nom qu'on désire lui donner.

En C/C++ il existe six sortes d'entiers. Les char (sur 8 bits) peuvent représenter des nombres entiers de -128 à +127. Les short (sur16 bits) vont aller de -32768 à 32767 (32k), et les long de -2147483648 à 2147483647 (2G). Si jamais les valeurs négatives ne sont pas utiles, on peut utiliser les unsigned char (sur 1 octet) qui peuvent représenter des nombres entiers de 0 à 255. Les unsigned short (sur 2 octets) vont aller de 0 à 65535 (64k), et les unsigned long de 0 à 4G. Ces types (précis) sont utiles si l'on cherche à gagner de la mémoire (dans le cas de nombreuses variables) ou que l'on tente de faire correspondre un nombre exact de bits avec un certain nombre d'entrées ou sorties (en informatique industrielle). Certains compilateurs acceptent également des long long sur 64 bits.

Mais la plupart du temps, on utilisera le type int, qui sera choisi par le compilateur de manière à être le plus efficace possible, tout en permettant de gérer au minimum les entiers entre -32768 et 32767 (Turbo C++ il prend des short, gcc prend des long).

Attention, le compilateur ne prévoit pas de tester les dépassements de capacité, c'est à vous de le faire. Si jamais vous dépassez le plus grand entier positif prévu par le type que vous avez choisi, il repart du plus petit ! Donc pour un char, après 127 il considère qu'il y a -128, pour un unsigned short après 65535 il repasse à 0.

4.2) Expressions, affectation

Une expression est un calcul qui donne une valeur résultat (exemple : 8+5). Une expression comporte des variables, des appels de fonction et des constantes combinés entre eux par des opérateurs (ex : MaVariable*sin(VarAngle*PI/180) ).

Une expression de base peut donc être un appel à une fonction (exemple sin(3.1416). Une fonction est un bout de programme (que vous avez écrit ou faisant partie d'une bibliothèque) auquel on "donne" des valeurs (arguments), entre parenthèses et séparés par des virgules. La fonction fait un calcul sur ces arguments pour "retourner" un résultat. Ce résultat pourra servir, si nécessaire, dans une autre expression, voire comme argument d'une fonction.

Dans une expression, on peut imposer l'ordre des calculs à l'aide des parenthèses (sans parenthèses, c'est le compilateur qui choisit l'ordre, d'après des règles bien précises et connues des programmeurs).

Une expression peut aussi comporter une affectation. Elle est utilise le signe =, et signifie que l'on veut mettre un nombre dans une variable. L'ordinateur détermine (évalue) tout d'abord la valeur à droite du signe =, en faisant tous les calculs nécessaires, puis elle est transférée dans la mémoire dont le nom est indiqué à gauche du =. Si nécessaire, le résultat d'une affectation est la valeur qu'on a transférée dans la mémoire. Cela n'a pas grand chose à voir avec l'égalité mathématique :

4.3) opérateurs sur les entiers

Il existe 5 opérations sur les entiers. Ce sont + (addition), - (soustraction), * (produit), / (division), % (reste de la division). Si vous ne mettez pas de parenthèses, * et / ont une priorité supérieure à + et -. Attention, pour les multiplications l'étoile est obligatoire (a*b et pas ab). Le résultat de ces opérations est toujours du même type que ces deux arguments, quand ils ont du même type (s'ils sont d'un type différent, voir plus loin). Donc 11/3 donnera 3, et pas 3,6666. 11%3 donnera 2. C'est comme à l'école primaire : 11 divisé par 3 donne 3 reste 2.

4.4) les flottants

En informatique, on n'arrive pas à gérer tous les nombres réels. On ne peut que les approximer par une suite finie de chiffres. En fait l'ordinateur gère les réels avec une méthode proche de la notation scientifique : 123,45 = 1,2345 102 (noté 1.2345E2 en C). Ce qui différenciera donc les types de nombres réels sera le nombre de chiffres significatifs pris en compte. Attention, l'ordinateur utilise des chiffres en binaire, c'est pourquoi l'indication d'un nombre de chiffres en décimal sera approximative. Il existe trois types de réels, les float (jusqu'à 1,7E38 mais avec uniquement 7 chiffres décimaux significatifs), les long float ou double (jusqu'à plus de 1E300, avec 15 chiffres significatifs, et les long double (non normalisés) encore plus précis.

Les 4 opérations possibles sont +, -, *, / (ici la division donnera un flottant, il n'y a pas de reste).

4.5) le cast

Lorsque, dans une expression, les deux opérandes sont de type différent (mais numérique évidement), le compilateur prévoit une conversion implicite (vous ne l'avez pas demandée mais il la fait néanmoins) suivant l'ordre : { char -> short -> long -> float -> double } et { signed -> unsigned }. le « plus petit » est automatiquement transformé dans le type du « plus grand », le résultat de l'opération sera lui aussi du type du plus grand. Par contre, le cast n'est appliqué automatiquement que si c'est nécessaire : si un opérateur est entouré de short, l'opération est faite sur des short, le résultat (short) pouvant toujours être transformé plus tard si nécessaire.

Pour forcer un cast, il suffit d'indiquer le type désiré entre parenthèses, devant la valeur à transformer (comme vous placez le signe - devant un nombre pour lequel vous désirez changer le signe). Exemple : (float)3 vaut 3 en flottant (vous pouviez aussi directement écrire 3.0). Vous pouvez également forcer un cast vers un type « plus petit » : dans ce cas là il y a risque de perte d'information. Exemple : (int)3.9 donnera 3 (partie entière), (unsigned char)256 donnera 0 (j'ai déjà dit qu'après le dernier il repassait à 0).

exemples :

int a=64,b=2; 
float x=1,y=2; 
b=7/b;/* signe = donc en premier calcul de l'argument à droite : 7 (entier) / 2 (entier) donne 3 (entier, reste 1, que l'on obtiendrait par 5%2). donc b=3 */
x=7/b;/* 7 et b entiers => passage en réel inutile, calcul de 7/3 donne 2 (entier, reste 1) puis opérateur = (transformation du 2 en 2.0 puis transfert dans X qui vaut donc 2.0) */
x=7/y;/* un int et un float autour de / : transformation implicite de 7 en réel (7.0), division des deux réel (3.5), puis transfert dans x */
x=7.0/b;/* un int et un float autour de / : transformation implicite de b en réel, division des deux réel (3.5), puis transfert dans x */
x=((float)(a+1))/b;/* calcul (entier) de a+1, puis transformation explicite en float, et donc implicite de b en float, division 65.0/3.0 -> 21.666... */

4.5) retour sur la structure d'un petit programme

Donc refaisons un nouveau programme. Lorsque, dans notre commerce, nous vendons plusieurs objets d'un même prix unitaire, nous aimerions connaître le prix total. De quelles variables aurons nous besoin ? Le prix unitaire et le prix total sont des flottants (si l'on a des prix avec des centimes). Nommons les PU et PTot. Par contre le nombre d'objets est entier, nommons le N.

Comme nous allons utiliser le clavier et l'écran, il nous faut inclure iostream.h. Puis nous allons passer au programme, il faut y mettre son entête et l'encadrer entre accolades. Nous commençons par spécifier (on dit déclarer) les variables nécessaires. Puis il faut demander à l'utilisateur de notre programme le prix unitaire et le nombre d'objets. On pourra alors calculer le prix total (n'oubliez pas l'ordre : en premier, l'ordinateur calcule combien vaut l'expression à droite du signe =, puis met ce nombre dans la variable identifiée à gauche du =). Il ne faudra pas oublier de l'afficher à l'écran, car à la fin du programme toutes les variables seront libérées, comme à la fin d'une recette de cuisine on lave et range le matériel.

#include <iostream.h>
int main(void)
 {
  float PU, PTot;
  int N;
  cout<<"veuillez entrer le prix unitaire : ";
  cin>>PU;
  cout<<"veuillez entrer le nombre d'objets : ";
  cin>>N;
  PTot=PU*N;
  cout<<"prix total : "<<PTot<<"\n";
 }

suivant retour  sommaire du cours C++ precedent Patrick TRAU, ULP - IPST octobre 04