Translate

الأربعاء، 20 نوفمبر 2013

Langage C++

                                 Historique de C++


Très tôt, les concepts de la programmation orientée objet (en abrégé P.O.O.) ont donné naissance

à de nouveaux langages dits « orientés objets » tels que Smalltalk, Simula, Eiffel ou,

plus récemment, Java. Le langage C++, quant à lui, a été conçu suivant une démarche

hybride. En effet, Bjarne Stroustrup, son créateur, a cherché à adjoindre à un langage structuré
existant (le C), un certain nombre de spécificités lui permettant d’appliquer les concepts

de P.O.O. Dans une certaine mesure, il a permis à des programmeurs C d’effectuer une transition

en douceur de la programmation structurée vers la P.O.O. De sa conception jusqu’à sa
normalisation, le langage C++ a quelque peu évolué. Initialement, un certain nombre de

publications de AT&T ont servi de référence du langage. Les dernières en date sont : la version
2.0 en 1989, les versions 2.1 et 3 en 1991. C’est cette dernière qui a servi de base au travail

du comité ANSI qui, sans la remettre en cause, l’a enrichie de quelques extensions et

surtout de composants standard originaux se présentant sous forme de fonctions et de classes

génériques qu’on désigne souvent par le sigle S.T.L (Standard Template Library). La norme

définitive de C++ a été publiée par l’ANSI en juillet 1998.



                             1 Présentation par l’exemple de quelques

                              instructions du langage C++

                            1.1 Un exemple de programme en langage C++




Voici un exemple de programme en langage C++, accompagné d’un exemple d’exécution.

Avant de lire les explications qui suivent, essayez d’en percevoir plus ou moins le fonctionnement.

#include <iostream>

#include <cmath>

using namespace std ;

main()


{ int i ;

float x ;


float racx ;

const int NFOIS = 5 ;

cout << "Bonjour\n" ;

cout << "Je vais vous calculer " << NFOIS << " racines carrees\n" ;

for (i=0 ; i<NFOIS ; i++)

{ cout << "Donnez un nombre : " ;

cin >> x ;

if (x < 0.0)

cout << "Le nombre " << x << "ne possede pas de racine carree\n " ;

else

{ racx = sqrt (x) ;

cout << "Le nombre " << x << " a pour racine carree : " << racx << "\n" ;
}
}
cout << "Travail termine - au revoir " ;
}
Bonjour

Je vais vous calculer 5 racines carrees

Donnez un nombre : 8
Le nombre 8 a pour racine carree : 2.82843

Donnez un nombre : 4
Le nombre 4 a pour racine carree : 2

Donnez un nombre : 0.25
Le nombre 0.25 a pour racine carree : 0.5

Donnez un nombre : 3.4
Le nombre 3.4 a pour racine carree : 1.84391

Donnez un nombre : 2
Le nombre 2 a pour racine carree : 1.41421
Travail termine - au revoir




                      1.3 Déclarations

                     Les quatre instructions :



int i ;

float x ;

float racx ;

const int NFOIS = 5 ;


sont des « déclarations ».

La première précise que la variable nommée i est de type int, c’est-à-dire qu’elle est destinée


à contenir des nombres entiers (relatifs). Nous verrons qu’en C++ il existe plusieurs types

d’entiers.

Les deux autres déclarations précisent que les variables x et racx sont de type float, c’est-àdire

qu’elles sont destinées à contenir des nombres flottants (approximation de nombres

réels). Là encore, nous verrons qu’en C++ il existe plusieurs types flottants.

Enfin, la quatrième déclaration indique que NFOIS est une constante de type entier, ayant la

valeur 5. Contrairement à une variable, la valeur d’une constante ne peut pas être modifiée.

En C++, comme dans la plupart des langages actuels, les déclarations des types des variables

sont obligatoires. Elles doivent apparaître avant d’être effectivement utilisées. Ici, nous les

avons regroupées au début du programme (on devrait plutôt dire : au début de la fonction

main). Il en ira de même pour toutes les variables définies dans une fonction ; on les appelle

« variables locales » (en toute rigueur, les variables définies dans notre exemple sont des

variables locales de la fonction main). Nous verrons également (dans le chapitre consacré

aux fonctions) qu’on peut définir des variables en dehors de toute fonction : on parlera alors

de variables globales.




                          1.9 L’instruction using



La norme de C++ a introduit la notion d’« espaces de noms » (namespace). Elle permet de

restreindre la « portée » des symboles à une certaine partie d’un programme et donc, en particulier,


de règler les problèmes qui peuvent se poser quand plusieurs bibliothèques utilisent

les mêmes noms. Cette notion d’espace de noms sera étudiée par la suite. Pour l’instant, retenez


que les symboles déclarés dans le fichier iostream appartiennent à l’espace de noms std.

L’instruction using sert précisément à indiquer que l’on se place « dans cet espace de noms


std » (attention, si vous placez l’instruction using avant l’incorporation des fichiers en-tête,

vous obtiendrez une erreur car vous ferez référence à un espace de noms qui n’a pas encore

été défini !).




                      1.10 Exemple de programme utilisant le type caractère


Voici un second exemple de programme, accompagné de deux exemples d’exécution, destiné

à vous montrer l’utilisation du type « caractère ». Il demande à l’utilisateur de choisir une

opération parmi l’addition ou la multiplication, puis de fournir deux nombres entiers ; il affiche

alors le résultat correspondant.

#include <iostream>

using namespace std ;

main()

{ char op ;

int n1, n2 ;

cout << "opération souhaitée (+ ou *) ? " ;

cin >> op ;

cout << "donnez 2 nombres entiers : " ;

cin >> n1 >> n2 ;

if (op == ’+’) cout << "leur somme est : " << n1+n2 << "\n" ;

else cout << "leur produit est : " << n1*n2 << "\n" ;

}
opération souhaitée (+ ou *) ? +

donnez 2 nombres entiers : 25 13





                               2.4 Le format libre


Comme tous les langages récents, le C++ autorise une mise en page parfaitement libre. En

particulier, une instruction peut s’étendre sur un nombre quelconque de lignes, et une même

ligne peut comporter autant d’instructions que vous le souhaitez. Les fins de ligne ne jouent

pas de rôle particulier, si ce n’est celui de séparateur, au même titre qu’un espace, sauf dans

les « constantes chaînes » où elles sont interdites ; de telles constantes doivent impérativement

être écrites à l’intérieur d’une seule ligne. Un identificateur ne peut être coupé en deux

par une fin de ligne, ce qui semble évident.

Bien entendu, cette liberté de mise en page possède des contreparties. Notamment, le risque

existe, si l’on n’y prend garde, d’aboutir à des programmes peu lisibles.

À titre d’exemple, voyez comment pourrait être (mal) présenté notre programme précédent :




                            1 La notion de type



La mémoire centrale est un ensemble de positions binaires nommées bits. Les bits sont regroupés


en octets (8 bits), et chaque octet est repéré par ce qu’on nomme son adresse.

L’ordinateur, compte tenu de sa technologie actuelle, ne sait représenter et traiter que des

informations exprimées sous forme binaire. Toute information, quelle que soit sa nature,

devra être codée sous cette forme. Dans ces conditions, on voit qu’il ne suffit pas de connaître

le contenu d’un emplacement de la mémoire (d’un ou de plusieurs octets) pour être en

mesure de lui attribuer une signification. Par exemple, si vous savez qu’un octet contient le

« motif binaire » suivant :

01001101


vous pouvez considérer que cela représente le nombre entier 77 (puisque le motif ci-dessus

correspond à la représentation en base 2 de ce nombre). Mais pourquoi cela représenterait-il

un nombre ? En effet, toutes les informations (nombres entiers, nombres réels, nombres complexes,

caractères, instructions de programme en langage machine, graphiques, images, sons,

vidéos...) devront, au bout du compte, être codées en binaire.

Dans ces conditions, les huit bits ci-dessus peuvent peut-être représenter un caractère ; dans

ce cas, si nous connaissons la convention employée sur la machine concernée pour représenter


les caractères, nous pouvons lui faire correspondre un caractère donné (par exemple M,

dans le cas du code ASCII). Ils peuvent également représenter une partie d’une instruction

machine ou d’un nombre entier codé sur 2 octets, ou d’un nombre réel codé sur 4 octets, ou...

On comprend donc qu’il n’est pas possible d’attribuer une signification à une information

binaire tant que l’on ne connaît pas la manière dont elle a été codée. Qui plus est, en général,

il ne sera même pas possible de « traiter » cette information. Par exemple, pour additionner

deux informations, il faudra savoir quel codage a été employé afin de pouvoir mettre en

oeuvre les bonnes instructions (en langage machine). Par exemple, on ne fait pas appel aux

mêmes circuits électroniques pour additionner deux nombres codés sous forme « entière » et

deux nombres codés sous forme « flottante ».

D’une manière générale, la notion de type, telle qu’elle existe dans les langages évolués, sert


à régler (entre autres choses) les problèmes que nous venons d’évoquer.

Les types de base du langage C++ se répartissent en quatre catégories en fonction de la

nature des informations qu’ils permettent de représenter :

• nombres entiers (mot-clé int) ;

• nombres flottants (mot-clé float ou double) ;

• caractères (mot-clé char) ;

• valeurs booléennes, c’est-à-dire dont la valeur est soit vrai, soit faux (mot-clé bool).





                          2 Les types entiers

                     2.1 Les différents types usuels d’entiers prévus par C++



C++ prévoit que, sur une machine donnée, on puisse trouver jusqu’à trois tailles différentes

d’entiers, désignées par les mots-clés suivants :

• short int (qu’on peut abréger en short) ;

• int (c’est celui que nous avons rencontré dans le chapitre précédent) ;

• long int (qu’on peut abréger en long).

Chaque taille impose naturellement ses limites. Toutefois, ces dernières dépendent non seulement

du mot-clé considéré, mais également de la machine utilisée : tous les int n’ont pas la

même taille sur toutes les machines ! Fréquemment, deux des trois mots-clés correspondent à

une même taille1.





                       2.2 Leur représentation en mémoire





Pour fixer les idées, nous raisonnerons ici sur des nombres entiers représentés sur 16 bits ,

mais il sera facile de généraliser notre propos à une taille quelconque.

Quelle que soit la machine (et donc, a fortiori, le langage !), les entiers sont codés en utilisant


un bit pour représenter le signe (0 pour positif et 1 pour négatif).

a) Lorsqu’il s’agit d’un nombre positif (ou nul), sa valeur absolue est écrite en base 2, à la


suite du bit de signe. Voici quelques exemples de codages de nombres (à gauche, le nombre

en décimal, au centre, le codage binaire correspondant, à droite, le même codage exprimé en

hexadécimal) :

1 0000000000000001 0001
2 0000000000000010 0002
3 0000000000000011 0003
16 0000000000010000 0010
127 0000000001111111 007F
255 0000000011111111 00FF

b) Lorsqu’il s’agit d’un nombre négatif, sa valeur absolue est codée généralement suivant ce

que l’on nomme la « technique du complément à deux »2. Pour ce faire, cette valeur est d’abord

exprimée en base 2 puis tous les bits sont inversés (1 devient 0 et 0 devient 1) et, enfin, on

ajoute une unité au résultat. Voici quelques exemples (avec la même présentation que

précédemment) :

-1 1111111111111111 FFFF
-2 1111111111111110 FFFE
-3 1111111111111101 FFFD
-4 1111111111111100 FFFC
-16 1111111111110000 FFF0
-256 1111111100000000 FF00

1. Dans une implémentation donnée, on peut connaître les caractéristiques des différents types entiers grâce à des

constantes (telles que INT_MAX, INT_MIN) définies dans le fichier en-tête climits.

2. Bien que non imposée totalement par la norme, cette technique tend à devenir universelle. Dans les

 (anciennes)*


mineures (deux représentations du zéro : +0 et -0, différence d’une unité sur la plage des valeurs couvertes pour une




                                               Remarques



1 Le nombre 0 est codé d’une seule manière (0000000000000000).

2 Si l’on ajoute 1 au plus grand nombre positif (ici 0111111111111111, soit 7FFF en

hexadécimal ou 32768 en décimal) et que l’on ne tient pas compte de la dernière retenue



(ou, ce qui revient au même, si l’on ne considère que les 16 derniers bits du résultat),

on obtient... le plus petit nombre négatif possible (ici 1000000000000000, soit

8000 en hexadécimal ou -32768 en décimal). Nous verrons qu’en C++, la situation dite

« de dépassement de capacité » (correspondant au cas où un résultat d’opération

s’avère trop grand pour le type prévu) sera traité ainsi, en ignorant un bit de retenue...

taille d’entier donnée).





                     2.3 Les types entiers non signés


De façon quelque peu atypique, C++ vous autorise à définir trois autres types voisins des précédents


en utilisant le qualificatif unsigned. Dans ce cas, on ne représente plus que des nombres

positifs pour lesquels aucun bit de signe n’est nécessaire. Cela permet théoriquement de

doubler la taille des nombres représentables ; par exemple, avec 16 bits, on passe de l’intervalle

[-32768; 32767] à l’intervalle [0 ; 65535]. Mais cet avantage est bien dérisoire, par rapport

aux risques que comporte l’utilisation de ces types (songez qu’une simple expression

telle que n-p va poser problème dès que la valeur de p sera supérieure à celle de n !).

En pratique, ces types non signés seront réservés à la manipulation directe d’un « motif

binaire » (tel un « mot d’état ») et non pas pour faire des calculs. Nous verrons d’ailleurs

qu’il existe des opérateurs spécialisés dits « de manipulation de bits ». Comme nous aurons

l’occasion de le rappeler, il est conseillé d’éviter de méler des entiers signés et des entiers





                           2.4 Notation des constantes entières


La façon la plus naturelle d’introduire une constante entière dans un programme est de

l’écrire simplement sous forme décimale, avec ou sans signe, comme dans ces exemples :

+533 48 -273

Vous pouvez également utiliser une notation octale (base 8) ou hexadécimale (base 16). La


forme octale se note en faisant précéder le nombre écrit en base 8 du chiffre 0.

Par exemple :

014 correspond à la valeur décimale 12,

037 correspond à la valeur décimale 31.

La forme hexadécimale se note en faisant précéder le nombre écrit en hexadécimal (les dix

premiers chiffres se notent 0 à 9, A correspond à dix, B à onze... F à quinze) des deux caractères

0x (ou 0X). Par exemple :

0x1A correspond à la valeur décimale 26 (16+10)

non signés dans une même expression, même si cela est théoriquement autorisé par la norme.

Les deux dernières notations doivent cependant être réservées aux situations dans lesquelles

on s’intéresse plus au motif binaire qu’à la valeur numérique de la constante en question.

D’ailleurs, ces constantes sont de type non signé (alors que les constantes écrites en notation

décimale sont bien signées).







                      Informations complémentaires


Par défaut, une constante entière écrite en notation décimale est codée dans l’un des deux

types signé int ou long (on utilise le type le plus petit, suffisant pour la représenter). On

peut imposer à une constante décimale

- d’être non signée, en la suffixant par « u », comme dans : 1u ou -25u ;

- d’être du type long, en la suffixant par « l », comme dans 456l ;

- d’être du type unsigned long en la suffixant par « ul », comme dans 2649ul.

Là encore, ces



                       3 Les types flottants

                   3.1 Les différents types et leur représentation en mémoire

Les types flottants permettent de représenter, de manière approchée, une partie des nombres

réels. Pour ce faire, ils s’inspirent de la notation scientifique (ou exponentielle) bien connue

qui consiste à écrire un nombre sous la forme 1.5 1022 ou 0.472 10-8 ; dans une telle notation,

on nomme « mantisses » les quantités telles que 1.5 ou 0.472 et « exposants » les quantités

telles que 22 ou -8.

Plus précisément, un nombre réel sera représenté en flottant, en déterminant deux quantités

M (mantisse) et E (exposant) telles que la valeur  M . B E

représente une approximation de ce nombre. La base B est généralement unique pour une

machine donnée (il s’agit souvent de 2 ou de 16) et elle ne figure pas explicitement dans la

représentation machine du nombre.

C++ prévoit trois types de flottants correspondant à des tailles différentes : float, double et

long double.

La connaissance des caractéristiques exactes du système de codage n’est généralement pas

indispensable, sauf lorsque l’on doit faire une analyse fine des erreurs de calcul1. En revan-




che, il est important de noter que de telles représentations sont caractérisées par deux

éléments :

• La précision : lors du codage d’un nombre décimal quelconque dans un type flottant, il est

nécessaire de ne conserver qu’un nombre fini de bits. Or la plupart des nombres s’exprimant

avec un nombre limité de décimales ne peuvent pas s’exprimer de façon exacte dans un tel

codage. On est donc obligé de se limiter à une représentation approchée en faisant ce que

l’on nomme une erreur de troncature. Quelle que soit la machine utilisée, on est assuré que

cette erreur (relative) ne dépassera pas 10-6 pour le type float et 10-10 pour le type long double.

• Le domaine couvert, c’est-à-dire l’ensemble des nombres représentables à l’erreur de troncature

près. Là encore, quelle que soit la machine utilisée, on est assuré qu’il s’étendra au

moins de 10-37 à 10+37.





                     4 Les opérateurs relationnels


Comme tout langage, C++ permet de comparer des expressions à l’aide d’opérateurs classiques

de comparaison. En voici un exemple :

2 * a > b + 5

Le résultat de la comparaison est une valeur booléenne prenant l’une des deux valeurs true ou

false.

Les expressions comparées pourront être d’un type de base quelconque et elles seront soumises

aux règles de conversion présentées dans le paragraphe précédent. Cela signifie qu’au bout

du compte on ne sera amené à comparer que des expressions de type numérique, même si

dans les opérandes figurent des valeurs de type short, char ou bool (true>false sera vraie).

Voici la liste des opérateurs relationnels existant en C++ :



                      Opérateur Signification


< inférieur à

<= inférieur ou égal à

> supérieur à

>= supérieur ou égal à

== égal à

!= différent de


Remarquez bien la notation (==) de l’opérateur d’égalité, le signe = étant réservé aux affectations.

En ce qui concerne leur priorité, il faut savoir que les quatre premiers opérateurs (<, <=, > et

>=) sont de même priorité. Les deux derniers (== et !=) possèdent également la même priorité,

mais celle-ci est inférieure à celle des précédents. Ainsi, l’expression :

a < b == c < d

est interprétée comme :

( a < b) == (c < d)

ce qui, en C++, a effectivement une signification, étant donné que les expressions a<b et c<d

sont, finalement, des quantités entières. En fait, cette expression prendra la valeur 1 lorsque

les relations a < b et c < d auront toutes les deux la même valeur, c’est-à-dire soit lorsqu’elles

seront toutes les deux vraies, soit lorsqu’elles seront toutes les deux fausses. Elle prendra la

valeur 0 dans le cas contraire.

D’autre part, ces opérateurs relationnels sont moins prioritaires que les opérateurs arithmétiques.

Cela permet souvent d’éviter certaines parenthèses dans des expressions.



                                11 L’opérateur conditionnel

                               Considérons l’instruction suivante :



if ( a>b )


max = a ;

else

max = b ;

Elle attribue à la variable max la plus grande des deux valeurs de a et de b. La valeur de max

pourrait être définie par cette phrase :

Si a>b alors a sinon b

En C++, il est possible, grâce à l’aide de l’opérateur conditionnel, de traduire presque littéralement

la phrase ci-dessus de la manière suivante :

max = a>b ? a : b

L’expression figurant à droite de l’opérateur d’affectation est en fait constituée de trois

expressions (a>b, a et b) qui sont les trois opérandes de l’opérateur conditionnel, lequel se

matérialise par deux symboles séparés : ? et :.

D’une manière générale, cet opérateur évalue la première expression qui joue le rôle d’une

condition. Comme toujours en C++, celle-ci peut être en fait de n’importe quel type. Si sa

valeur est différente de zéro, il y a évaluation du second opérande, ce qui fournit le résultat ;

si sa valeur est nulle, en revanche, il y a évaluation du troisième opérande, ce qui fournit le

résultat.

Voici un autre exemple d’une expression calculant la valeur absolue de 3*a + 1 :

3*a+1 > 0 ? 3*a+1 : -3*a-1

L’opérateur conditionnel dispose d’une faible priorité (il arrive juste avant l’affectation), de

sorte qu’il est rarement nécessaire d’employer des parenthèses pour en délimiter les différents


opérandes (bien que cela puisse parfois améliorer la lisibilité du programme). Voici,

toutefois, un cas où les parenthèses sont indispensables :

z = (x=y) ? a : b

Le calcul de cette expression amène tout d’abord à affecter la valeur de y à x. Puis, si cette

valeur est non nulle, on affecte la valeur de a à z. Si, au contraire, cette valeur est nulle, on


affecte la valeur de b à z.

Il est clair que cette expression est différente de :

z = x = y ? a : b

laquelle serait évaluée comme :

z = x = ( y ? a : b )

Bien entendu, une expression conditionnelle peut, comme toute expression, apparaître à son

tour dans une expression plus complexe. Voici, par exemple, une instruction (notez qu’il

s’agit effectivement d’une instruction, car elle se termine par un point-virgule) affectant à z la

plus grande des valeurs de a et de b :

z = ( a>b ? a : b ) ;

De même, rien n’empêche que l’expression conditionnelle soit évaluée sans que sa valeur*


soit utilisée comme dans cette instruction :

a>b ? i++ : i-- ;

Ici, suivant que la condition a>b est vraie ou fausse, on incrémentera ou on décrémentera la

variable i.





                                     13 L’opérateur sizeof



L’opérateur sizeof, dont l’emploi ressemble à celui d’une fonction, fournit la taille en octets

(n’oubliez pas que l’octet est, en fait, la plus petite partie adressable de la mémoire). Par

exemple, dans une implémentation où le type int est représenté sur 2 octets et le type double

sur 8 octets, si l’on suppose que l’on a affaire à ces déclarations :


int n ;

double z ;

• l’expression sizeof(n) vaudra 2 ;

• l’expression sizeof(z) vaudra 8.

Cet opérateur peut également s’appliquer à un type de nom donné. Ainsi, dans l’implémentation

précédemment citée :


• sizeof(int) vaudra 2 ;

• sizeof(double) vaudra 8.

Quelle que soit l’implémentation, sizeof(char) vaudra toujours 1 (par définition, en quelque


sorte).

Cet opérateur offre un intérêt :

• lorsque l’on souhaite écrire des programmes portables dans lesquels il est nécessaire de connaître

la taille exacte de certains éléments ;

• pour éviter d’avoir à calculer soi-même la taille d’objets d’un type relativement complexe

pour lequel on n’est pas certain de la manière dont il sera implémenté par le compilateur. Ce

sera notamment le cas des structures ou des objets.




                        3 L’instruction switch

                        3.1 Exemples d’introduction de l’instruction switch

                        a) Premier exemple



Voyez ce premier exemple de programme accompagné de trois exemples d’exécution.

#include <iostream>

using namespace std ;

main()

{ int n ;
cout << "donnez un entier : " ;

cin >> n ;

switch (n)

{ case 0 : cout << "nul\n" ;

break ;

case 1 : cout << "un\n" ;

break ;

case 2 : cout << "deux\n" ;

break ;

}
cout << "au revoir\n" ;

}

donnez un entier : 0

nul

au revoir

donnez un entier : 2

deux

au revoir

donnez un entier : 5

au revoir






                            2.3 Imbrication des instructions if



Nous avons déjà mentionné que les instructions figurant dans chaque partie du choix d’une

instruction pouvaient être absolument quelconques. En particulier, elles peuvent, à leur tour,

renfermer d’autres instructions if. Or, compte tenu de ce que cette instruction peut comporter

ou ne pas comporter de else, il existe certaines situations où une ambiguïté apparaît. C’est le

cas dans cet exemple :


if (a<=b) if (b<=c) cout << "ordonné" ;

else cout << "non ordonné" ;

Est-il interprété comme le suggère cette présentation ?


if (a<=b) if (b<=c) cout << "ordonné" ;

else cout << "non ordonné" ;

ou bien comme le suggère celle-ci ?

if (a<=b) if (b<=c) cout << "ordonné" ;

else cout << "non ordonné" ;

La première interprétation conduirait à afficher "non ordonné" lorsque la condition a<=b est

fausse, tandis que la seconde n’afficherait rien dans ce cas. La règle adoptée par le langage

C++ pour lever une telle ambiguïté est la suivante :

Dans notre exemple, c’est la seconde présentation qui suggère le mieux ce qui se passe.

Voici un exemple d’utilisation de if imbriqués. Il s’agit d’un programme de facturation avec

remise. Il lit en donnée un simple prix hors taxes et calcule le prix TTC correspondant (avec

un taux de TVA constant de 19,6 %). Il établit ensuite une remise dont le taux dépend de la

valeur ainsi obtenue, à savoir :

• 0 % pour un montant inférieur à 1 000 euros ;

Un else se rapporte toujours au dernier if rencontré auquel un else n’a pas encore

été attribué.

Les instructions de contrôle

• 1 % pour un montant supérieur ou égal à 1 000 euros et inférieur à 2 000 euros ;
• 3 % pour un montant supérieur ou égal à 2 000 euros et inférieur à 5 000 euros ;
• 5 % pour un montant supérieur ou égal à 5 000 euros.

#include <iostream>

using namespace std ;

main()

{ const double TAUX_TVA = 19.6 ;

double ht, ttc, net, tauxr, remise ;

cout << "donnez le prix hors taxes : " ;

cin >> ht ;

ttc = ht * ( 1. + TAUX_TVA/100.) ;

if ( ttc < 1000.) tauxr = 0 ;

else if ( ttc < 2000 ) tauxr = 1. ;

else if ( ttc < 5000 ) tauxr = 3. ;

else tauxr = 5. ;

remise = ttc * tauxr / 10

0. ;

net = ttc - remise ;

cout << "prix ttc = " << ttc << "\n" ;

cout << "remise = " << remise << "\n" ;

cout << "net à payer = " << net << "\n" ;
}
donnez le prix hors taxes : 500

prix ttc = 598

remise = 0

net à payer = 598

donnez le prix hors taxes : 4000

prix ttc = 4784

remise = 143.52

net à payer = 4640.48

ليست هناك تعليقات:

إرسال تعليق