structure de donn�e

Document Sample
structure de donn�e Powered By Docstoc
					INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAGE ... Page 1 of 63

INITIATION A LA PROGRAMMATION STRUCTURÉE AVEC LE LANGAGE C++
Denis Bureau et Michel Couprie. © Groupe E.S.I.E.E. 2002
Composé avec LATEX ( version 2001 ) ( version 2000 ) ( version 1999 )

Table des matières
1 Les ``briques de base'' de la construction de programmes 1.1 Un programme très simple 1.2 Commentaires 1.3 Identificateurs 1.4 Affichage de messages 1.5 Notion de type de données 1.6 Constantes 1.7 Variables 1.8 Place des déclarations 1.9 Affichage de valeurs 1.10 Acquisition de valeurs numériques 2 Types de données 2.1 Type int 2.1.1 Représentation des valeurs 2.1.2 Opérateurs arithmétiques 2.1.3 Opérateurs relationnels 2.1.4 Fonctions mathématiques 2.2 Type double 2.2.1 Représentation 2.2.2 Opérateurs arithmétiques 2.2.3 Opérateurs relationnels 2.2.4 Fonctions mathématiques 2.3 Type char 2.3.1 Représentation des valeurs 2.3.2 Opérateurs arithmétiques 2.3.3 Opérateurs relationnels 2.3.4 Fonctions usuelles 2.4 Type bool 2.4.1 Opérateurs logiques 2.5 Conversions de type 2.6 Représentation interne 3 Expressions arithmétiques et logiques 4 Instructions, Structure séquentielle 4.1 Affectation 4.2 Instruction composée 5 Structures alternatives 5.1 Choix simple

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAGE ... Page 2 of 63

5.2 Choix multiple 5.2.1 Exercices 6 Structures répétitives 6.1 Structure ``Tant que'' (while ) 6.2 Structure ``Faire ... Tant que'' (do ... while ) 6.3 Structure ``Pour'' (for ) 6.4 Boucles imbriquées 7 Sous-programmes (fonctions et procédures) 7.1 Exécution d'un sous-programme 7.2 Définition de fonctions 7.3 Appel d'une fonction 7.4 Procédures 7.5 Paramètres 7.6 Définition de procédure 7.7 Appel d'une procédure 7.8 Règles de visibilité 7.9 Notion de ``prototype'' 7.10 Quand créer des sous-programmes ? 7.11 Recommandations 8 Définition de nouveaux types de données 8.1 Type défini par synonymie 8.2 Type défini par énumération 8.2.1 Valeur des éléments 8.2.2 Opérations sur une variable de type énuméré 8.2.3 Vérifications de type à la compilation 9 Types structurés : tableaux 9.1 Définition 9.2 Type des composantes 9.3 Tableau à 2 dimensions 9.4 Tableau multidimensionels 9.5 Tableaux et paramètres 9.6 Référence à un élément du tableau 9.7 Tableaux de caractères 9.8 Lecture / écriture de tableaux 9.8.1 Tableaux numériques 9.8.2 Tableaux de caractères 9.9 Dangers des tableaux 9.10 Exercices 9.10.1 Tableaux de dimension 1 9.10.2 Tableaux à plusieurs dimensions 10 Types structurés : structures hétérogènes (struct) 10.1 Définition 10.2 Accès aux composantes 10.3 Passage d'une structure en paramètre 11 Pointeurs 11.1 Définition d'un type pointeur 11.2 Variables de type pointeur 11.3 Valeurs de pointeurs - l'opérateur & 11.4 Accès à l'objet ``pointé'' - l'opérateur * 11.5 Pointeur NULL 11.6 Allocation de mémoire - l'opérateur new 11.7 Libération de mémoire - l'opérateur delete 11.8 Pointeurs et tableaux 11.9 Pointeurs et structures 11.10 Listes chaî nées

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAGE ... Page 3 of 63

12 Fichiers de texte 12.1 Inclusion 12.2 Déclaration (et ouverture) 12.3 Lecture 12.4 Écriture 12.5 Fermeture 12.6 Passage de paramètres 12.7 Conclusion 13 Du C++ au C-ANSI 13.1 Entête 13.2 Affichage 13.3 Saisie 13.4 Type de données logiques 13.5 Allocation dynamique 13.6 Passage de paramètre par adresse 13.7 Fichiers de texte 13.7.1 Inclusion 13.7.2 Déclaration (et ouverture) 13.7.3 Lecture 13.7.4 Écriture 13.7.5 Fermeture 14 Notions de logique booléenne 14.1 Valeurs possibles 14.2 Opérateurs 14.3 Tables de vérité 14.4 Règles de simplification 14.5 Évaluation en C++ 15 Bibliographie

Avertissement
Le but de ce document est de servir de support à un cours d'initiation à la programmation structurée . L'enseignement de la programmation ne peut se concevoir sans une importante part de travaux pratiques, durant laquelle les étudiants conçoivent et mettent au point leurs propres programmes, et tirent les conséquences de leurs erreurs. Le langage choisi pour les travaux pratiques est un sous-ensemble du C++ qui concilie la simplicité et la modularité du Pascal à l'avantage de se rapprocher des standards de programmation du moment. Ce compromis doit avoir pour effet de faciliter le passage soit vers le C-ANSI1, soit vers le C++ au sens orienté objet (voire vers Java), éventuellement en auto-formation. Le présent document n'est donc pas un cours de langage C++. Nous ne présentons ici que ce qui est strictement indispensable à la progression pédagogique. En particulier, l'aspect orienté objet n'est pas abordé dans ce cours. L'étudiant désirant aller plus loin dans la connaissance de C++ trouvera facilement, dans les manuels de référence et les nombreux ouvrages qui lui sont consacrés, des présentations plus exhaustives. Cependant, il est préférable à notre avis de maîtriser parfaitement le contenu du présent cours avant d'explorer les autres possibilités du langage.

Introduction
Un programme informatique est constitué d'ordres simples, bien définis et dont l'effet est parfaitement

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAGE ... Page 4 of 63

connu. Mais un grand programme, qui peut comporter des millions de ces ordres élémentaires, est un objet très complexe, susceptible de réponses ou de comportements surprenants, et parfois même pouvant sembler ``intelligents''. Cette complexité est la principale difficuté que doit vaincre le concepteur de programmes informatiques. Autant il est facile de concevoir sans méthode un programme de quelques dizaines d'instructions, autant il est nécessaire de s'imposer des règles de conception et de construction pour maîtriser la complexité des grands programmes. Les notions clés qui permettent cette maîtrise de la complexité sont : modularité et structuration. La modularité, c'est l'application de l'adage : diviser pour vaincre. On résoud plus facilement un problème complexe en le décomposant en plusieurs sous-problèmes de difficulté moindre. Encore faut-il que ces sous-problèmes soient relativement indépendants. La structuration vient naturellement lorsqu'on décompose une tâche en sous-tâches, qui elles-mêmes se décomposent à leur tour en sous-sous-tâches, etc. Le résultat obtenu prend alors une forme - une structure - hiérarchique. Les principaux langages informatiques utilisés aujourd'hui (C, C++, Ada, Pascal, Java, etc.) permettent l'expression de programmes sous forme structurée, et comportent des outils (les procédures, les fonctions…) pour construire des modules. Ce cours a pour but, non d'enseigner seulement un langage, mais d'introduire à travers un sous-ensemble du langage C++ ces notions très générales qui servent de base à toute conception méthodique de programmes (quel que soit le langage utilisé).

1 Les ``briques de base'' de la construction de programmes
1.1 Un programme très simple
Exemple 1
#include <iostream.h> int main() { cout << "bienvenue a l'ESIEE" << endl; return 0; }

Ce premier exemple est l'un des plus courts que l'on puisse concevoir, sa seule fonction étant d'afficher un message (bienvenue à l'ESIEE ) sur l'écran de l'ordinateur. Sa première ligne :
#include <iostream.h>

sert à introduire des informations utiles au compilateur, concernant les fonctions standard d'entrée/sortie (Input/Output stream = flux d'entrée/sortie) comme celles permettant d'afficher des caractères à l'écran, de saisir des valeurs au clavier, etc. Nous retrouverons donc cette entête dans tous les programmes réalisant des entrées/sorties. Les mots-clés int main (main signifie : principal, et nous reviendrons plus tard sur le sens de int)

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAGE ... Page 5 of 63

introduisent le corps du programme principal. Celui-ci se compose d'un bloc d'instructions, délimité par les symboles accolades { et }. Sa dénomination vient du fait qu'il peut faire appel à des programmes auxiliaires, ou sous-programmes. La seule instruction de ce programme d'exemple (cout ...) affiche le message de bienvenue à l'écran. Notez les guillemets ("), qui servent à délimiter le message, et le symbole endl (end of line), qui provoque un passage du curseur à la ligne suivante, après l'affichage du message. Notez également l'opérateur << qui doit précéder, dans une instruction cout, chaque partie de message. Le point-virgule (;) termine l'instruction. Notez enfin la dernière instruction qui permet de retourner un code d'erreur au système d'exploitation (ici, 0 signifie qu'il n'y a pas d'erreur); cette syntaxe sera expliquée au chapitre 7.2 sur les fonctions En dehors des zones entre guillemets, les blancs ou espaces, retours à la ligne et tabulations peuvent être utilisés pour améliorer la présentation des programmes. Le compilateur les traite comme des séparateurs de symboles, et ignore ceux qui sont superflus.

1.2 Commentaires
Exemple 2
/* Ce programme resoud les systemes lineaires par la methode de Gauss */ #include <iostream.h> int main() { ...

Sur la première ligne de l'exemple ci-dessus, on trouve un texte délimité par les signes ``/*'' au début et ``*/'' à la fin. C'est un commentaire . Facultatifs, les commentaires servent à introduire en marge d'un programme des explications favorisant la lisibilité, mais qui n'interviennent pas dans le programme luimême. Ils peuvent être introduits à n'importe quel endroit dans le programme (sauf à l'intérieur d'un mot ou d'un symbole), pour éclairer le sens de définitions, de modules, d'instructions, etc.

1.3 Identificateurs
Les identificateurs sont les noms des objets qui apparaissent dans vos programmes. Dans l'exemple suivant, il y a trois identificateurs : les noms Dividende, Diviseur et Quotient qui désignent des variables servant à stocker des entiers relatifs. Des identificateurs sont également utilisés pour définir des constantes , des types de données , des fonctions (nous examinerons ces notions dans la suite du cours). Exemple 3
#include <iostream.h> int main() { int Dividende, Diviseur, Quotient; Dividende = 24; Diviseur = 3; Quotient = Dividende / Diviseur; cout << Quotient << endl; return 0; }

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAGE ... Page 6 of 63

Un identificateur se compose de caractères alphanumériques (lettres et chiffres). Le signe souligné ``_'' (underscore) peut également être utilisé dans un identificateur. Un identificateur débute obligatoirement par une lettre ou par un ``_'' . Le nombre de caractères que peut comporter un identificateur dépend de votre compilateur (par exemple pour Turbo-C: nombre de caractères quelconque, mais seuls les 32 premiers caractères sont significatifs). Les majuscules et les minuscules sont des caractères différents : ainsi les identificateurs NAME, Name et name sont différents les uns des autres. Attention cependant : les mots de la liste suivante sont réservés et ne peuvent être réutilisés : asm class double friend new register struct union auto break catch case char const continue default delete do else enum extern float for goto if inline int long operator overload private protected public return short signed sizeof static switch this template try typedef unsigned virtual void volatile while Mots réservés du C++ Il est possible d'éviter de tomber accidentellement sur un de ces mots en commençant systématiquement ses identificateurs par une majuscule.

1.4 Affichage de messages
Dans l'exemple 1.1 , la seule instruction exécutable est une instruction d'affichage annoncée par l'ordre cout (de l'anglais Channel OUTput , canal de sortie. Prononcez : "cé-a-outte"). Les ordres d'affichage :
cout << element; cout << element1 << element2 << element3;

provoquent l'affichage des éléments annoncés par le signe << . Si l'élément est entre guillemets (") alors le texte est imprimé littéralement. Pour inclure un guillemet dans un texte à afficher littéralement, il faut le faire précéder d'une barre oblique ( \ ), pour éviter que celui-ci soit interprété comme la fin du texte : instruction : cout << "imprime \" et le reste" imprime " et le reste effet à l'écran : Pour introduire un saut de ligne, on peut inclure dans la chaîne de caractères la séquence \n . Ainsi, l'instruction d'affichage :
cout << "Les sanglots longs\n des violons\n de l'automne" << endl;

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAGE ... Page 7 of 63

donne l'effet suivant à l'écran :
Les sanglots longs des violons de l'automne

En fin d'affichage il est préférable pour passer à la ligne suivante d'utiliser le symbole endl, qui a également pour effet de forcer un affichage immédiat à l'écran. Exercice 1 Écrire le programme qui fait afficher le texte suivant :
"... diviser chacune des difficultes que j'exprimerais en autant de parties qu'il se pourrait et qu'il serait requis pour les mieux resoudre." Rene DESCARTES Le Discours de la Methode (1637)

1.5 Notion de type de données
En mathématique, nous distinguons les nombres entiers naturels, les entiers relatifs, les rationnels, etc. En informatique, nous distinguons de même différents types de nombres, notamment des nombres de type int (en anglais integer = entier) et double (nombres à virgule flottante en double précision). int et double sont deux types de données élémentaires . Leur but est de modéliser en machine les éléments de ces ensembles mathématiques idéaux, sans vraiment y parvenir, car la place en mémoire que l'on peut consacrer au stockage d'un nombre est forcément limitée. Dans la pratique, la place qu'occupe un nombre de type int est, par exemple, 32 bits, ce qui limite l'intervalle des entiers représentables à [−231, +231−1] . Nous reviendrons plus en détail dans la suite sur cette notion de type de données.

1.6 Constantes
Il est conseillé, pour la lisibilité et la maintenabilité des programmes, de substituer aux valeurs numériques brutes des symboles les représentant : ce sont les constantes. Par exemple : Exemple 4
const double PI = 3.1415; const double ACCPESANTEUR = 9.81; const int NBREMAX = 30;

Dans cet exemple, les mots : double et int définissent le type de la constante. Dans la suite du programme, on pourra faire référence à ces valeurs par leur nom, par exemple : Exemple 5
cout << "perimetre du disque de rayon 1 = "; cout << 2 * PI; cout << endl;

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAGE ... Page 8 of 63

Autre exemple : Exemple 6
const int COTE_CARRE = 5; const int SURFACE_CARRE = COTE_CARRE * COTE_CARRE; const int PERIMETRE_CARRE = COTE_CARRE * 4;

Dans cette exemple, il suffit de changer la valeur de la constante COTE_CARRE pour que les valeurs des deux autres constantes soient recalculées en conséquence.

1.7 Variables
Une variable est une unité de stockage qui permet de mémoriser, durant l'exécution du programme, une information d'un type donné. Les variables doivent être définies avant leur utilisation : Exemple 7
/* declaration de variables */ int NombreDeDisques; double Rayon, Surface;

1.8 Place des déclarations
La place dans un programme des déclarations de constantes et de variables est importante. C'est cette place qui, dans un programme complexe, détermine la zone où les objets déclarés pourront être utilisés (portée d'une déclaration). Dans un programme simple ne comportant qu'un seul bloc d'instructions (délimité par les accolades et }), la place des déclarations est au début du bloc : juste après l'accolade ouvrante {, et avant la première instruction exécutable (voir l'exemple 1.3 ).

{

1.9 Affichage de valeurs
Nous avons vu comment afficher un message sous forme littérale : si l'élément à afficher est entre guillemets (") alors le texte sera imprimé littéralement. Sinon, c'est qu'il s'agit d'une variable, d'une constante ou du résultat d'un calcul dont la valeur sera affichée : Exemple 8
cout << (ACCPESANTEUR * (1 - 0.01)); cout << Surface;

1.10 Acquisition de valeurs numériques
La plupart des programmes nécessitent une interaction avec un utilisateur. Nous venons de voir comment le programme peut communiquer des informations à l'utilisateur en affichant des messages et des données à l'écran. L'utilisateur doit pouvoir, lui aussi, communiquer des informations au programme. C'est le but de l'ordre d'acquisition cin (de l'anglais Channel INput , canal d'entrée.

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAGE ... Page 9 of 63

Prononcez : "cé-inne"). Exemple 9
cout << "donnez la valeur du rayon : " cin >> Rayon;

En exécutant ces deux instructions, le programme s'interrompt après avoir affiché le message ``donnez la valeur du rayon :'' . Il attend que l'utilisateur tape un nombre au clavier (par exemple : 2.45) et qu'il valide l'opération grâce à la touche ``return''. La valeur saisie est alors stockée dans la variable Rayon . Remarque : le sens de circulation des données permet de se souvenir s'il faut employer << ou >> .

2 Types de données
Étudiez l'exemple suivant : Exemple 1
/* calcul de la surface d'un disque de rayon donne */ #include <iostream.h> int main() { const double PI = 3.14159; double Rayon, Surface; /* acquisition de la donnee */ cout << "rayon en m du disque " << "dont vous voulez connaitre la surface ? "; cin >> Rayon; /* traitement */ Surface = PI * Rayon * Rayon; /* affichage du resultat */ cout << "la surface du disque est de " << Surface << " metres carres." << endl; return 0; }

Uu seul type de données apparaît ici, c'est le type double (nombre à virgule flottante en double précision). Les deux variables définies Rayon et Surface sont de ce type. Dans certains langages (comme Pascal) on nomme ce type ``réel''. On parle indifféremment de ``flottants'' ou nombres à ``virgule flottante'' (floating point) par référence à la notation mantisseexposant, qui permet de placer la virgule ou le point décimal à n'importe quel endroit :

1.234567 = 123.4567E−2 = 0.001234567E3 Dans les exemples précédents, nous avons également rencontré des variables de type int (entier relatif).

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 10 of 63

Plus généralement, un type est un ensemble de données de même nature régies par des règles communes. Nous aborderons dans un premier temps les types simples prédéfinis, et nous verrons par la suite comment le programmeur peut définir de nouveaux types de données. Les 4 types simples prédéfinis que nous utiliserons dans ce cours correspondent respectivement aux entiers relatifs, aux nombres à virgule flottante en double précision, aux caractères, et aux valeurs logiques. Ce sont :

int double char bool
2.1 Type int
Le type
int

(de l'anglais INTeger, entier) correspond à un entier relatif stocké sur un nombre de bits qui dépend du système (machine et compilateur) utilisé. En turbo-C (v 2.0) sur un compatible PC par exemple, un int était stocké sur 16 bits (nombre à 16 chiffres en numération binaire), et était compris entre −215( = − 32768) et +215−1( = 32767) . Sur la plupart des stations de travail, un int est stocké sur 32 bits, et donc compris entre −231 et +231−1 . 2.1.1 Représentation des valeurs Une valeur entière en notation décimale s'exprime comme une succession de chiffres décimaux (entre 0 et 9) précédés ou non d'un signe. Exemple 2
27500 -123 +418

2.1.2 Opérateurs arithmétiques +
*

additition

− soustraction multiplication / division % modulo Opérateurs arithmétiques pour les entiers L'opérateur / sert à calculer le quotient de la division entière. Exemple 3
13 / 5 vaut 2 1998 / 10 vaut 199

Note : le même opérateur / sert également pour la division de nombres de type double. Il s'agira d'une

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 11 of 63

division entière seulement si les deux opérandes de la division sont de type entier. L'opérateur % (modulo) sert à calculer le le reste de la division entière. Exemple 4
13 1998 7 8 % 5 % 10 % 2 % 2 vaut vaut vaut vaut 3 8 1 0

Le lecteur averti aura noté que l'opération ``modulo 2'' permet de tester la parité d'un entier, et que l'opération ``modulo 10'' permet d'extraire le chiffre des unités pour la notation décimale d'un entier. 2.1.3 Opérateurs relationnels
== != < <= > >=

égal différent inférieur strict inférieur ou égal supérieur strict supérieur ou égal

Opérateurs relationnels 2.1.4 Fonctions mathématiques nom type param type retour
abs

int

int

rôle valeur absolue d'un int

Pour utiliser cette fonction dans votre programme, vous devrez placer en en-tête la directive :
#include <math.h>

Nous verrons au chapitre 7.2 p.pageref comment définir de nouvelles fonctions (non prévues dans le standard C++).

2.2 Type double
Le type
double

correspond aux nombres à virgule flottante en double précision, stockés usuellement sur 64 bits. Il existe également un type float donnant une moins grande précision. Usuellement les variable de type float sont stockées sur 32 bits. 2.2.1 Représentation La forme générale des valeurs de type double est :

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 12 of 63

[ ± ] chiffres[.chiffres ] [ E [±] chiffres ] ou bien : [ ± ] .chiffres [ E [±] chiffres ] (les éléments entre crochets [ ] sont optionnels). Exemple 5
2.3 -12E6 +123.456E-20 .123

2.2.2 Opérateurs arithmétiques +
*

additition

− soustraction multiplication / division

Opérateurs arithmétiques pour les nombres de type double 2.2.3 Opérateurs relationnels Ce sont les mêmes que pour les entiers. 2.2.4 Fonctions mathématiques Dans les programmes devant effectuer des calculs, il est souvent nécessaire d'avoir recours à des fonctions de la bibliothèque mathématique . Voici celles qui sont le plus souvent utilisées : nom type param type retour acos double double
asin atan ceil cos exp fabs floor log sin sqrt

rôle arc cosinus arc sinus arc tangente arrondi à la valeur supérieure cosinus exponentielle valeur absolue d'un double arrondi à la valeur inférieure logarithme néperien sinus racine carrée

double double double double double double double double double double

double double double double double double double double double double

Fonctions usuelles de la bibliothèque mathématique Pour utiliser ces fonctions dans votre programme, vous devrez placer en en-tête la directive :

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 13 of 63

#include <math.h>

Voici un exemple d'utilisation de la fonction sqrt (racine carrée = square root ) : Exemple 6
#include <iostream.h> #include <math.h> int main() { cout << "Le Nombre d'Or vaut : " << (sqrt(5) + 1) / 2 << endl; return 0; }

2.3 Type char
Le type
char

représente l'ensemble de tous les caractères imprimables et non imprimables ordonnés selon le code ASCII (chaque caractère est représenté par un entier entre 0 et 127) : ... < '0' < '1' < ... < '9' < ...'A' < 'B' < ...'Z' < ... < 'a' < 'b' < ... < 'z' < ... 2.3.1 Représentation des valeurs Les valeurs des caractères imprimables sont représentées entre apostrophes. Exemple 7
char LettreMajuscule; LettreMajuscule = 'A';

Pour certains caractères ``spéciaux'' souvent utilisés (la tabulation, le retour à la ligne…) il existe une notation mnémonique :
'\t' '\n' '\\' tab (tabulation) newline (retour a la ligne) \

Pour les autres, il suffit de connaître leur code ASCII. On utilisera la forme :
(char)N

pour désigner la valeur du caractère dont le code ASCII est N. De façon analogue, si C est une variable de type char,
(int)C

désigne le code ASCII du caractère C (entier compris entre 0 et 127).

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 14 of 63

Exemple 8
#include <iostream.h> int main() { const char BIP = (char)7; /* code ascii 7 = bip sonore */ char carac; cin >> carac; if (carac == 'A') cout << BIP; return 0; } /* saisie d'un caractere au clavier */ /* si c'est un A, alors */ /* emet un bip sonore */

2.3.2 Opérateurs arithmétiques Les caractères étant codés par des entiers, on peut leur appliquer les mêmes opérateurs, notamment l'addition et la soustraction. A charge pour le programmeur de vérifier que de telles opérations ont un sens. Exemple 9
/* conversion d'une majuscule en minuscule */ carac = carac + 'a' - 'A';

2.3.3 Opérateurs relationnels Ce sont les mêmes que pour les entiers. 2.3.4 Fonctions usuelles Ces fonctions servent, soit à tester si un caractère donné appartient à un certain ensemble (par exemple les lettres minuscules), soit à transformer un caractère (par exemple, mise en majuscule d'une lettre). nom type param type retour isdigit char int
isalpha isalnum iscntrl islower isupper tolower toupper

rôle est-ce un chiffre ? est-ce une lettre ? est-ce un chiffre ou une lettre ? est-ce un caractère non imprimable ? est-ce une lettre minuscule ? est-ce une lettre majuscule ? transforme en minuscule transforme en majuscule

char char char char char char char

int int int int int char char

Fonctions usuelles de traitement d'un caractère Pour utiliser ces fonctions dans votre programme, vous devrez placer en en-tête la directive :
#include <ctype.h>

2.4 Type bool

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 15 of 63

La logique dite ``booléenne'' s'intéresse aux fonctions dont les espaces de départ et d'arrivée sont réduits à 2 éléments :
faux vrai

Malgré son apparence modeste, cet ensemble est très utile pour construire des expressions logiques complexes, mémoriser des conditions de test, etc. Pour plus de détails, se reporter au chapitre 14 . En C, il n'existe pas de type ``booléen'' particulier. On représente la valeur ``faux'' par l'entier 0, et la valeur ``vrai'' par toute autre valeur entière (généralement 1). En C++, il existe le type ``bool'', ainsi que les deux constantes true et false , correspondant respectivement aux valeurs vrai et faux. Attention ! A l'affichage, ces deux valeurs apparaissent respectivement comme 1 et 0. 2.4.1 Opérateurs logiques
&& || !

et ou non

Opérateurs logiques Exemple 10
#include <iostream.h> int main() { bool b; b = (true || false) && ! false; cout << "b = " << b << endl; /* quelle sera la valeur imprimee ? */ return 0; }

2.5 Conversions de type
Il est souvent nécessaire de convertir une valeur d'un type à un autre pour le besoin d'un calcul, ou de faire participer à une même opération des objets de types différents (par exemple double et int). Certaines conversions sont implicites, mais d'une façon générale il est préférable de les rendre explicites en préfixant l'objet à convertir par le type que l'on veut lui attribuer, entre parenthèses :
(NomType)NomObjet

comme nous l'avons vu avec les conversions entier-caractère (section 2.3 ). Cette opération est connue dans la ``littérature'' anglophone sous le nom de cast . Attention : la conversion de type peut occasionner une perte d'information, comme dans le cas d'une conversion double → int. Dans ce cas en effet, c'est la partie entière de la valeur qui est conservée.

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 16 of 63

Exemple 11
double D; int I; /* ... */ I = (int)D; I = D;

/* I recoit la partie entiere de D

*/

/* meme effet, mais provoque de la part */ /* du compilateur un message d'avertissement */

2.6 Représentation interne
L'ANSI-C et le C++ permettent de représenter les nombres différemment suivant les plate-formes matérielles et logicielles. Les exemples qui suivent ne s'appliquent qu'au logiciel Borland C++, mais ils illustrent bien la diversité des types numériques.

Sur une architecture 32 bits :
Type Taille (en octets) 1 1 2 4 4 4 4 4 8 10 Intervalle Applications

char unsigned char short int unsigned int int long unsigned long float double long double

-128 à +127 0 à 255 -32.768 à +32.767 0 à 4.294.967.295 -2.147.483.648 à +2.147.283.647 -2.147.483.648 à +2.147.283.647 0 à 4.294.967.295 ±3.4 × 10−38 à ±3.4 × 10+38 ±1.7 × 10−308 à ±1.7 × 10+308 ±3.4 × 10−4932 à ±1.1 × 10+4932

très petits nombres et caractères ASCII petits nombres et caractères compteurs de boucles et nombres pas trop grands nombres en général grands nombres grands nombres distances astronomiques calcul scientifique avec 7 chiffres significatifs calcul scientifique avec 15 chiffres significatifs calcul financier avec 18 chiffres significatifs

Sur une architecture 16 bits :
Type Taille (en octets) 1 1 2 2 2 Intervalle Applications

char unsigned char short int int unsigned int

-128 à +127 0 à 255 -32.768 à +32.767 -32.768 à +32.767 0 à 65.535

très petits nombres et caractères ASCII petits nombres et caractères compteurs de boucles et nombres pas trop grands compteurs de boucles et nombres pas trop grands compteurs de boucles et nombres en général

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 17 of 63

long unsigned long float double long double

4 4 4 8 10

-2.147.483.648 à +2.147.283.647 0 à 4.294.967.295 ±3.4 × 10−38 à ±3.4 × 10+38 ±1.7 × 10−308 à ±1.7 × 10+308 ±3.4 × 10−4932 à ±1.1 × 10+4932

grands nombres distances astronomiques calcul scientifique avec 7 chiffres significatifs calcul scientifique avec 15 chiffres significatifs calcul financier avec 18 chiffres significatifs

3 Expressions arithmétiques et logiques
Une expression est une combinaison cohérente, éventuellement parenthésée, d'opérandes et d'opérateurs qui sont évalués pour donner une valeur. Opérande valeur constante variable appel de fonction (standard ou définie par le programmeur) Opérateurs arithmétiques : * / % + relationnels : == != < <= > >= logiques : ! && || En cas d'ambiguïté, l'évaluation a lieu selon l'ordre de priorité suivant : 1. 2. 3. 4. 5. 6. 7. 8. 9. la parenthèse ( ) la plus interne les fonctions ! signe * / % + < <= > >= == != && ||

A priorité égale, évaluation de gauche à droite. Pour les expressions booléennes de type A && B (A et B), l'opérande droit (B) n'est évalué que si nécessaire. En effet, si l'évaluation de A donne la valeur logique ``faux'', la valeur de l'expression est ``faux'' quelle que soit la valeur de B, il est donc inutile d'évaluer B. Il en est de même pour les expressions de la forme A || B (A ou B) , lorsque l'évaluation de l'opérande gauche (A) donne ``vrai'' (voir également le chapitre 14 p.pageref). Il est préférable, en général, d'utiliser les parenthèses pour rendre explicite l'ordre dans lequel les opérations doivent s'effectuer. Non seulement cela évite d'avoir à connaître la table des priorités sur le bout des doigts, mais cela facilite beaucoup la lecture du programme. Attention ! Les opérateurs == et != ne doivent pas être utilisés avec des données de type double à cause

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 18 of 63

de problèmes de précision, surtout quand ces données sont issues d'un calcul. Il faut donc remplacer if (X == Y) par if ( fabs( X - Y ) < PRECISION ) où PRECISION est une constante préalablement définie (1E-9 par exemple). C'est également pour cette raison que les programmes manipulant des données comptables n'utilisent pas de nombres réels, car les résultats doivent toujours tomber juste au centime près. Exercice 1 Que valent ces expressions ?
1 + 2/3 (1 < 2) || (1 > 2) ( (12.2 + sin(4 + 1.8e2) * 3) < 123 ) && !( 2 + 2 == 4 )

4 Instructions, Structure séquentielle
Exemple 1
#include <iostream.h> #include <math.h> int main() { double X, Y; cin >> X; Y = sin(X); cout << Y << endl; return 0; }

/* declarations */ /* acquisition d'une valeur */ /* calcul et memorisation du sinus de X */ /* affichage du resultat */

Le programme ci-dessus comporte, dans sa partie exécutable, une séquence de trois instructions. Cela signifie qu'elles seront exécutées l'une après l'autre , dans l'ordre de leur apparition dans le programme. La première :
cin >> X;

est une instruction d'entrée (input), une valeur est attendue du clavier puis stockée dans la variable X. La seconde :
Y = sin(X);

est une instruction d'affectation , le sinus de la valeur stockée dans X est calculé puis stocké dans la variable Y. La troisième :
cout << Y << endl;

est une instruction de sortie (output), la valeur stockée dans la variable Y est affichée à l'écran. Ces trois instructions sont regroupées en une instruction composée (ou bloc d'instructions) délimitée par les accolades { et } . Nous connaissons donc trois formes d'instruction : Affectation - instruction composée - entrée / sortie

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 19 of 63

4.1 Affectation
La forme générale d'une instruction d'affectation est :

VARIABLE = EXPRESSION; L'expression est d'abord évaluée, puis le résultat de cette évaluation est stocké dans la variable. Un cas particulier d'affectation est particulièrement fréquent et possède une syntaxe simplifiée. Il s'agit de l'opération d'incrément qui consiste à augmenter d'une unité le contenu d'une variable. Sous sa forme standard, l'opération d'incrément peut s'écrire :
VARIABLE = VARIABLE + 1;

Sous la forme condensée, on peut écrire l'instruction logiquement équivalente :

VARIABLE++; L'opération inverse, nommée décrément , possède également une forme condensée, ainsi
VARIABLE = VARIABLE - 1;

est logiquement équivalent à :

VARIABLE- -;

4.2 Instruction composée
La forme générale d'une instruction composée est :

{ Declarations Locales (facultatives) INSTRUCTION1 INSTRUCTION2 ... INSTRUCTIONn }

Les instructions formant la séquence sont exécutées l'une après l'autre, dans l'ordre où elles sont écrites. Remarque : chaque instruction composée ou bloc peut comporter au début une ou plusieurs déclarations locales. Les objets définis localement ne sont utilisables (``visibles'') que dans le bloc dans lequel ils sont définis. Note importante : une instruction simple se termine par un point-virgule. Une instruction composée se termine par une accolade fermante. Exercice 1 En choisissant des noms de variables adéquats et en définissant toutes les constantes nécessaires, écrire les déclarations et instructions C++ qui correspondent aux formules ci-dessous :

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 20 of 63

La période t d'un pendule de longueur l est donnée par

t = 2π

  √

l g

où g est la constante gravitationelle (9,81 m/s2) La surface d'un triangle dont les côtés ont pour longueur a, b, et c est

_____________ s = √p(p−a)(p−b)(p−c) où p est le demi-périmètre du triangle. Exercice 2 Ecrire un programme qui effectue la conversion en centimètre s d'une longueur exprimée en mètres et en centimètres. Exercice 3 Ecrire un programme qui saisit trois nombres et les affiche dans l'ordre inverse de l'ordre de saisie. Exercice 4 Un nombre rationnel s'exprime sous la forme [P/Q] où P et Q sont des entiers. Ecrire un programme qui saisit deux entiers correspondants à P et Q et affiche le nombre réel correspondant en notation décimale. Exercice 5 Ecrire un programme qui saisit un entier positif n et affiche la somme des n premiers entiers (sans faire une boucle !). Exercice 6 Ecrire un programme qui saisit les coordonnées des sommets d'un triangle et qui affiche le périmètre et la surface de ce triangle.

5 Structures alternatives
5.1 Choix simple
Lorsqu'un traitement doit être subordonné à une condition, on utilise la structure :

if (EXPRESSION_BOOLEENNE) INSTRUCTION

A l'exécution, l'EXPRESSION BOOLÉENNE est évaluée. Ce peut être une comparaison, une variable de type int dont la valeur sera interprétée comme un booléen, ou une quelconque expression logique. Si l'évaluation de cette expression donne la valeur logique ``vrai'' (toute valeur différente de 0), l'INSTRUCTION est exécutée, sinon elle ne l'est pas et l'on passe à la suite du programme. Notez bien que l'INSTRUCTION peut être une instruction composée (un bloc délimité par { et } ). Exemple 1
/* resolution d'une equ. du second degre a coeff. non nuls */

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 21 of 63

#include<iostream.h> #include<math.h> int main() { double A, B, C, Delta; /* acquisition */ cout << "entrez les valeurs des coefficients A, B, et C non nuls"; cout << endl; cin >> A >> B >> C; /* traitement et affichage des resultats */ Delta = B * B - 4 * A * C; if (Delta == 0) cout << "X1 = X2 = " << -B / (2 if (Delta > 0) { cout << "X1 = " << (-B + sqrt(Delta)) / (2 * cout << "X2 = " << (-B - sqrt(Delta)) / (2 * } if (Delta < 0) cout << "pas de racines reelles" return 0; }

* A) << endl; A) << endl; A) << endl; << endl;

Lorsque le choix entre deux traitements est subordonné à une condition, on utilise la structure :

if (EXPRESSION_BOOLEENNE) INSTRUCTION1 else INSTRUCTION2

A l'exécution, l'EXPRESSION BOOLÉENNE est évaluée ; si l'évaluation de cette expression donne la valeur logique ``vrai'' (toute valeur différente de 0), l'INSTRUCTION1 est exécutée, sinon c'est l'INSTRUCTION2 qui est exécutée. INSTRUCTION1 et INSTRUCTION2 peuvent être des instructions simples ou composées. Note : si INSTRUCTION1 est une instruction simple (non composée), elle doit obligatoirement se terminer par un point-virgule, même si la présence du mot-clé else indique que l'instruction if n'est pas terminée. Exemple 2
/* affiche le plus grand de deux nombres lus */ #include<iostream.h> int main() { double X, Y, Max; /* acquisition */ cout << "entrez deux nombres separes par un espace" << endl; cin >> X >> Y; /* traitement */ if (X > Y) Max = X; else Max = Y; /* affichage du resultat */

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 22 of 63

cout << Max << " est le plus grand de " << X << " et de " << Y << endl; return 0; }

5.2 Choix multiple
Lorsque le choix entre divers traitements dépend de la valeur d'une seule expression, on peut utiliser la structure :

switch (EXPRESSION) { case CONSTANTE1 : LISTE_INSTRUCTIONS1 break; case CONSTANTE2 : LISTE_INSTRUCTIONS2 break; ... case CONSTANTEn : LISTE_INSTRUCTIONSn break; default: LISTE_INSTRUCTIONSn+1; }

L'EXPRESSION est tout d'abord évaluée. Le fonctionnement est le suivant : Si la valeur de l'EXPRESSION est égale à la CONSTANTE1, alors la LISTE_INSTRUCTIONS1 est exécutée. Sinon, si la valeur de l'EXPRESSION est égale à la CONSTANTE2, alors la LISTE_INSTRUCTIONS2 est exécutée, etc. Si la valeur de l'EXPRESSION n'est égale à aucune des constantes, alors la LISTE_INSTRUCTIONSn+1 est exécutée. Remarques : Notez le break à la fin de chaque instruction, sauf la dernière. Il sert à ``sauter'' l'évaluation des cas suivants, lorsqu'une comparaison a réussi. L'exécution reprend alors après l'accolade fermante du switch . Le type de l'expression et des constantes doit être un type de base non réel, ou un type énuméré (voir chapitre 8.2 ).
switch

Si une même instruction doit être exécutée pour différentes valeurs de constantes, on peut utiliser dans le la forme :

case CONSTANTE1 : case CONSTANTE2 : case CONSTANTE3 : LISTE_INSTRUCTIONS break; ...

Exemple 3 Le programme suivant détermine si le jour de la semaine donné en entrée est un jour ouvré ou un jour chômé.
/* determination de jour ouvre */ #include<iostream.h> int main() { int Jour; char Boulot; /* acquisition */ cout << "entrez un jour de la semaine" << endl

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 23 of 63

<< "(lundi: 1, mardi: 2,..., dimanche: 7)" << endl; cin >> Jour; /* traitement */ switch (Jour) { case 1: case 2: case 3: case 4: case 5: Boulot case 6: case 7: Boulot default: Boulot } /* fin switch

= 't'; break; = 'r'; break; = 'e'; */

/* affichage du resultat */ switch (Boulot) { case 'e': cout << "erreur" << endl; case 'r': cout << "repos" << endl; case 't': cout << "travail" << endl; } /* fin switch */ return 0; }

break; break; break; /* facultatif */

5.2.1 Exercices Exercice 1 Ecrire un programme qui saisit trois nombres et affiche le plus petit. Exercice 2 Ecrire un programme qui saisit les coordonnées d'un point, du centre d'un cercle et la valeur du rayon du cercle, détermine si le point est à l'intérieur (au sens large), ou à l'extérieur (au sens strict) du cercle. Exercice 3 Ecrire un programme qui saisit les coordonnées de trois points et qui indique si ceux-ci sont alignés. Exercice 4 Ecrire un programme qui saisit un entier et qui, sans faire de calcul, affiche soit : ËRREUR" s'il n'est pas compris entre 1 et 10, soit : "P" s'il est premier, soit : "NP" s'il ne l'est pas.

6 Structures répétitives
6.1 Structure ``Tant que'' (while )
Lorsque l'on doit répéter un traitement tant qu' une condition reste vérifiée, on utilise la structure :

while (EXPRESSION_BOOLEENNE) INSTRUCTION

Lors de l'exécution de cette structure, l'EXPRESSION BOOLÉENNE est évaluée. Si elle est fausse, on quitte la structure et on passe à la suite du programme. Si elle est vraie, on exécute l'INSTRUCTION (qui peut bien sûr être une instruction composée), puis on retourne au début de la structure, c'est-à-dire au test de l'EXPRESSION BOOLÉENNE. Exemple 1

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 24 of 63

demande a l'utilisateur d'entrer une etoile (*) et insiste jusqu'a obtenir satisfaction */ #include <iostream.h> int main() { const char ETOILE = '*'; char Carac; /* initialisations */ Carac = ETOILE + 1; /* acquisition d'un caractere et traitement */ while (Carac != ETOILE) { cout << "entrez une " << ETOILE << " !!!" << endl; cin >> Carac; } /* fin while */ cout << "merci." << endl; return 0; }

/*

6.2 Structure ``Faire … Tant que'' (do … while )
Lorsque le traitement doit être effectué au moins une fois, on utilise cette variante de la structure précédente :

do INSTRUCTION while (EXPRESSION_BOOLEENNE)

Lors de l'exécution de cette structure, l'INSTRUCTION (qui peut bien sûr être une instruction composée) est exécutée une première fois, puis l'EXPRESSION BOOLÉENNE est évaluée. Si elle est fausse, on quitte la structure et on passe à la suite du programme. Si elle est vraie, on retourne au début de la structure, c'est-à-dire au début de l'INSTRUCTION. Exemple 2
demande a l'utilisateur d'entrer une etoile (*) et insiste jusqu'a obtenir satisfaction */ #include <iostream.h> int main() { const char ETOILE = '*'; char Carac; /* acquisition d'un caractere et traitement */ do { cout << "entrez une " << ETOILE << " !!!" << endl; cin >> Carac; } while (Carac != ETOILE); cout << "merci." << endl; return 0; } /*

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 25 of 63

Question : pourquoi n'est il plus nécessaire d'initialiser la variable Carac, comme dans l'exemple 6.1 ? Exemple 3
/* Compte le nombre de $ et de caracteres differents de $ entres par l'utilisateur. Celui-ci termine par le caractere * . */ #include <iostream.h> int main() { const char CARSPECIAL = '$'; const char CARFIN = '*'; int CompteSpecial, CompteNonSpecial; /* compteurs */ char Carac; /* initialisations */ CompteSpecial = 0; CompteNonSpecial = 0; Carac = CARFIN + 1; cout << "entrez des caracteres, terminez par *" << endl; /* acquisition d'un caractere et traitement */ while (Carac != CARFIN) { cin >> Carac; if (Carac == CARSPECIAL) CompteSpecial++; else CompteNonSpecial++; } /* fin while */ CompteNonSpecial--; /* on ne compte pas l'etoile */ /* affichage des resultats */ cout << endl << CompteSpecial << " " << CARSPECIAL << " et "; cout << CompteNonSpecial << " caracteres differents de "; cout << CARSPECIAL << endl; return 0; }

Exercice 1 Ecrire un programme qui saisit des caractères, séparés par des RETURN, jusqu'à trouver le caractère 'q' ou 'Q', et qui affiche pour chaque caractère saisi le code ASCII correspondant. Exercice 2 Si xn est une valeur approchée de √A, alors xn+1 = [1/2] ( xn + [A/(xn)] ) est une meilleure valeur approchée de √A. Ecrire un programme qui saisit une valeur réelle positive A et calcule sa racine carrée avec une précision telle que l'écart entre A et le carré de sa racine carrée ainsi estimée est inférieur à 10−6.

6.3 Structure ``Pour'' (for )
Lorsque l'on désire répéter un traitement un nombre de fois déterminé, on peut utiliser la structure :

for (INITIALISATION; TEST; INCREMENT) INSTRUCTION_FOR

L'instruction INITIALISATION est exécutée une fois et une seule au début de l'exécution du for.

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 26 of 63

L'expression booléenne TEST est évaluée avant chaque répétition éventuelle de l'INSTRUCTION_FOR. Si elle est fausse, on quitte la structure et on passe à la suite du programme. Si elle est vraie, on exécute l'INSTRUCTION_FOR (qui peut bien sûr être une instruction composée), puis l'instruction INCREMENT, et enfin on retourne à l'évaluation de TEST. L'instruction INCREMENT est exécutée après chaque exécution d'INSTRUCTION_FOR. Typiquement, elle sert à incrémenter un compteur. Exemple 4
#include <iostream.h> int main() { const int MAX = 5; int I; for (I = 1; I <= MAX; I++) cout << " " << I << " fois" << endl; return 0; } execution: 1 2 3 4 5 fois fois fois fois fois

Remarque : la variable servant de "compteur" n'est pas forcément un entier. Exemple 5
/* affichage des codes ASCII des caracteres entre Z et A */ #include <iostream.h> int main() { char Carac; for (Carac = 'Z'; Carac >= 'A'; Carac--) { cout << " caractere : " << Carac; cout << " code ASCII : " << (int)Carac; cout << endl; } /* fin for */ return 0; }

La variable servant de "compteur" (dite aussi variable de contrôle) est souvent utilisée à l'intérieur de la boucle pour des tests ou des calculs : Exemple 6
/* calcul de factorielle a l'aide d'une variable de controle */ #include <iostream.h> int main()

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 27 of 63

{ int I, N; double Produit; /* entree des donnees */ cout << "factorielle de ? "; cin >> N; /* traitement */ Produit = 1; for (I = 2; I <= N; I++) Produit = Produit * I; /* affichage du resultat */ cout << N << "! vaut " << Produit << endl; return 0; }

6.4 Boucles imbriquées
Il est courant d'avoir à imbriquer des boucles, particulièrement lorsque l'on traite des objets à plusieurs dimensions. Imaginez que vous ayez à examiner un damier : il vous faut examiner chacune des dix lignes, et pour chaque ligne, il faut examiner chacune des dix cases qui la constitue. Cela donne l'algorithme suivant :
pour LIGNE allant de 1 a 10 faire debut pour COLONNE allant de 1 a 10 faire EXAMINER_CASE(LIGNE, COLONNE) fin

Exemple 7 Écrire un programme qui saisit deux entiers au clavier, et qui affiche à l'écran un rectangle composé de caractères '*', dont les dimensions correspondent aux entiers saisis.
/* programme affichant un rectangle - exemple d'execution : entrez 2 entiers : 3 8 ******** ******** ******** */ #include <iostream.h> int main() { int I, J, NbLigne, NbColonne; cout << "entrez 2 entiers : "; cin >> NbLigne >> NbColonne; for (I = 0; I < NbLigne; I++) { for (J = 0; J < NbColonne; J++) { cout << "*"; } /* fin for J */ cout << endl; } /* fin for I */ return 0; }

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 28 of 63

Exercice 3 Ecrire un programme qui réalise le "dessin" suivant à l'aide de boucles imbriquées.
*.... .*... ..*.. ...*. ....* ..... ..... .....

7 Sous-programmes (fonctions et procédures)
Les sous-programmes (fonctions et procédures) offrent au programmeur le moyen de réaliser des modules de programmation relativement indépendants, réalisant chacun une tâche parfaitement définie, et pouvant être développés, vérifiés et testés séparément. Une fois écrit et mis au point, un sous-programme pourra être vu et utilisé comme une ``boîte noire'', dont on n'aura à connaître que le nom (symbolisant le calcul réalisé), et les paramètres d'entrée et de sortie. Prenons comme exemple une fonction que nous connaissons déjà, la fonction sin de la bibliothèque mathématique. Il se peut qu'un calcul compliqué soit réalisé pour trouver le sinus d'un nombre flottant, mais une fois la fonction sin définie, tout ce qu'il nous faut en savoir se résume au diagramme suivant :

7.1 Exécution d'un sous-programme
L'exécution d'une fonction, ou plus généralement d'un sous-programme, est provoquée par son appel qui figure dans le programme principal (ou dans un autre sous-programme). L'appel provoque un débranchement temporaire de l'exécution du programme principal (ou du sous-programme) appelant , qui est interrompu pour laisser s'exécuter le sous-programme appelé . Après la fin de l'exécution du sous-programme appelé, l'exécution du programme appelant reprend là où elle avait été interrompue. Exemple 1 Contenu du programme principal :
debut programme SEQUENCE 1 APPEL SOUS-PROGRAMME B SEQUENCE 2 APPEL SOUS-PROGRAMME A SEQUENCE 3 fin programme

Contenu (définition) du sous-programme B :
debut sous-programme SEQUENCE 4 APPEL SOUS-PROGRAMME A SEQUENCE 5

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 29 of 63

fin sous-programme

Exécution :
debut programme SEQUENCE 1 debut sous-programme B SEQUENCE 4 debut sous-programme A ... fin sous-programme A SEQUENCE 5 fin sous-programme B SEQUENCE 2 debut sous-programme A ... fin sous-programme A SEQUENCE 3 fin programme

7.2 Définition de fonctions
Nous connaissons une fonction standard prédéfinie : la fonction sin . Nous allons voir maintenant comment le programmeur peut définir, puis utiliser ses propres fonctions. La notion de fonction, en programmation, modélise la notion mathématique de fonction : à une valeur du paramètre x choisie dans un ensemble de départ (le domaine de définition de la fonction), on fait correspondre (on calcule) une valeur f(x) appartenant à l'ensemble d'arrivée. Il est également possible de définir des fonctions de plusieurs variables (f(x,y,z)) mais la valeur retournée est toujours unique. Voici tout d'abord un exemple de définition de fonction. Exemple 2
/* fonction a valeur entiere et parametre entier calculant le cube de l'argument */ int Cube (const int I) { return I * I * I; }

La forme générale d'une définition de fonction est la suivante : TypeRésultat NomFonction (déclarations de paramètres formels)
{

instructions

corps de la return expression; fonction
}

Remarques :

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 30 of 63

La définition d'une fonction doit prendre place avant les définitions de programme (ou sousprogrammes) appelant cette fonction. L'affectation d'une valeur de retour est obligatoire. L'instruction return... possède en fait deux rôles : interrompre l'exécution de la fonction et revenir au programme ou sous-programme appelant ; spécifier quelle sera la valeur retournée par la fonction. Les paramètres formels représentent les ëntrées" de la fonction. Ils doivent être accompagnés de leur type. Ils ne servent que pour la définition (leur nom peut être réutilisé sans ambiguïté dans un autre contexte). La présence du mot const n'est pas obligatoire, mais elle est fortement conseillée car elle informe le compilateur que le paramètre ne doit pas être modifié pendant toute la durée de la fonction. Si ce n'est pas le cas, le compilateur signale une erreur. Cas particulier de la fonction main() : Le compilateur exige que sa valeur de retour soit de type int car le programme a ainsi la possibilité de retourner un code d'erreur au système d'exploitation mais, malheureusement, il autorise l'absence totale de return dans le corps de la fonction main(). Dans tout programme propre, la fonction main() devrait se terminer par return 0; .

7.3 Appel d'une fonction
Voici un programme définissant et utilisant une fonction à deux paramètres, l'un entier, l'autre flottant, et retournant une valeur flottante : Exemple 3
/* exemple d'utilisation d'une fonction */ #include<iostream.h> /* =============================================== */ /* FONCTION: Puissance(R, I) */ /* calcule R a la puissance I (I positif ou nul) */ double Puissance (const double R, const int I) { int Compteur; /* compte le nombre de multiplications double Produit; /* stocke les produits partiels */ Produit = 1; for (Compteur = 1; Compteur <= I; Compteur++) Produit = Produit * R; return Produit; } /* fin fonction Puissance */ /* =============================================== */ /* PROGRAMME PRINCIPAL -- TEST DE : Puissance */ int main() { int N; double X, Y; cout << "entrez la valeur reelle: "; /* saisie */ cin >> X; cout << "entrez l'exposant entier non negatif: "; cin >> N; Y = Puissance(X, N); /* traitement */ cout << Y << endl; /* affichage */ return 0; }

*/

Remarques :

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 31 of 63

La correspondance entre les paramètres formels (utilisés lors de la définition) et les paramètres effectifs (utilisés lors de l'appel) se fait en parcourant les deux listes dans le même ordre. Les variables Compteur et Produit sont locales à la fonction PUISSANCE. Une fonction peut également appeler une autre fonction définie préalablement. Une fonction ne peut pas retourner un résultat de type tableau (voir le chapitre 9 ). Nous voyons maintenant que tous nos programmes principaux (main) étudiés jusqu'ici étaient en fait des fonctions sans paramètres (d'où la nécessité du return 0;). Un appel de fonction peut également faire partie d'une expression, ou être utilisée comme paramètre effectif : Exemple 4
#include <math.h> /* exemple de fonction a un parametre d'entree : tangente */ double Tan(const double x) { return sin(x) / cos(x); } /* exemples d'appel : */ x = Tan(2.3); if (Tan(Theta) < 1E-4) ... cout << 1 + ( exp(Tan(Alpha + Beta)) / 2) );

Exercice 1 Définir une fonction SinH qui admet un argument double et renvoie une valeur double. Le sinus hyperbolique est défini par la formule

sinh x =

ex−e−x 2

Incorporer SinH dans un programme adéquat. Exercice 2 Définir une fonction Factorielle qui admet un argument entier positif et renvoie une valeur entière. La fonction Factorielle associe à tout entier naturel n, un entier naturel usuellement noté n! défini par :

    

0! 1!

=1 =1

∀n > 1 n! = 2 ×3 ×…×n

Incorporer Factorielle dans un programme adéquat.

7.4 Procédures
Nous avons vu qu'une fonction retourne en résultat une valeur unique à chaque exécution. Que faire

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 32 of 63

lorsque nous avons besoin de produire, dans un même sous-programme, plusieurs résultats différents ? Ou pas de résultat du tout ? Les procédures répondent à ce besoin, en autorisant plusieurs genres de paramètres. Par contre, une procédure ne renvoie pas de valeur : tout se passe au niveau des paramètres. Une procédure se déclare grâce au mot-clé void (néant), qui précède le nom de la procédure lors de sa définition : Exemple 5
void Affiche_N_LignesBlanches(const int N) { int I; for ( I=0; I<N; I++ ) cout << endl; }

7.5 Paramètres
Nous pouvons logiquement distinguer trois genres de paramètres : les paramètres d'entrée, qui représentent des valeurs nécessaires au calcul effectué par la procédure, les paramètres de sortie, qui désignent les variables où devront être rangées les résultats du calcul, et enfin les paramètres mixtes, qui désignent des variables dans lesquelles se trouvent initialement des données nécessaires au calcul, et dont le contenu modifié par le calcul constituera un résultat. En fait, C++ distingue seulement deux modes de transmission de paramètres : les paramètres passés par valeur, qui conviennent aux paramètres d'entrée. Pour ces paramètres, leur valeur est recopiée temporairement dans une variable temporaire qui n'est accessible que durant l'exécution du sous-programme ; les paramètres passés par référence qui conviennent à la fois aux paramètres de sortie ou mixtes. Pour ces paramètres, c'est leur adresse en mémoire qui est rendue accessible au sous-programme, ce qui lui permet d'y lire et d'y écrire des informations. Note : Le mode de passage de paramètre par référence est spécifique au langage C++, et n'existe pas en C (sauf implicitement pour les données de type tableau, comme nous le verrons plus loin). Pour ``simuler'' en C un passage de paramètre par référence, il faudra utiliser les pointeurs , notion qui sera abordée au chapitre 11 . Pour les fonctions, nous n'avons envisagé que des paramètres d'entrée, passés par valeur. Cette convention est adoptée par la plupart des programmeurs. Pour indiquer qu'un paramètre doit être passé par référence, il faut faire précéder son nom du caractère & et ne pas mettre le mot const . Par exemple : Exemple 6
#include <iostream.h> /* exemple de procedure avec un parametre mixte : increment de N+1 unites */ void Incr(int & A, const int N) { A = A + N + 1; }

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 33 of 63

/* exemple d'appel : int main() { int B; B = 6; Incr(B, 4); cout << B << endl; return 0; }

*/

/*

que vaut B maintenant ?

*/

Mais attention : si une procédure possède un paramètre passé par référence, il est obligatoire d'utiliser une variable pour ce paramètre lors de l'appel : Exemple 7
/* avec la definition de l'exemple precedent: */ Incr(4, 1); /* INTERDIT: 4 est une constante, pas une variable */

Incr(B+1, 3); /* INTERDIT: B+1 est une expression, pas une variable */

7.6 Définition de procédure
La forme générale d'une définition de procédure est la suivante :
void { }

NomProcédure (déclaration de paramètres formels) Corps de la procédure

7.7 Appel d'une procédure
Un appel de procédure est de la forme : NomProcédure (liste de paramètres effectifs); Une procédure peut ne pas posséder de paramètre : Exemple 8
#include <iostream.h> /* exemple de procedure sans parametre : provoque un "beep" sonore void Beep() { cout << (char) 7; } /* appel : int main() { Beep(); return 0; } */ */

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 34 of 63

Exercice 3 Définir une procédure NBeep qui admet un paramètre entier N, et qui provoque consécutivement N "beeps" sonores : 1. avec une boucle "for" et un compteur local; 2. avec une boucle "while" et en utilisant le paramètre passé par valeur comme compteur. Exercice 4 Définir une procédure Equa2 qui prend comme paramètres d'entrée trois double a, b, c coefficients de l'équation du second degré :

a x2 + b x + c = 0 et qui possède trois paramètres de sortie : X1 et X2 de type double, représentant les racines réelles de l'équation si elles existent, et SolutionDansR, un booléen vrai s'il existe des racines réelles distinctes ou non, et faux sinon. Définir un environnement de test pour cette procédure (programme principal, éventuellement procédure auxiliaire pour le test), ainsi qu'un jeu de valeurs permettant de tester tous les cas différents pouvant se présenter.

7.8 Règles de visibilité
La première règle de visibilité est : un objet (constante, variable, type, etc) ne peut être utilisé que dans le bloc (programme ou sous-programme) dans lequel il est déclaré. Exemple 9
#include<iostream.h> int F1() { int I; I = 1; return I; } void P1() { cout << I; }

/* Variable LOCALE */ /* I est VISIBLE dans le bloc */ /* d'instructions de F1 */

/* ERREUR : I n'est pas visible HORS du bloc de F1 */

Des déclarations peuvent également apparaître en dehors de tous les blocs d'instructions, on dit alors qu'elles sont globales . Les objets ainsi définis peuvent être utilisés partout après leur définition. On peut donc considérer qu'il existe un bloc ``global'' qui inclut tous les autres. Exemple 10
#include<iostream.h> const double PI = 3.14159; double Perimetre (const double Rayon) { return 2 * PI * Rayon;

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 35 of 63

/* la constante PI est VISIBLE dans le bloc de Perimetre */ } /* ... */

Attention : dans le cas où un objet global et un objet local portent exactement le même nom, c'est la définition la plus locale qui prime. Les définitions globales de constantes peuvent se révéler indispensables lorsque des paramètres de sousprogrammes utilisent ces définitions. L'exemple suivant utilise une constante dont le caractère global est impératif. Exemple 11
#include<iostream.h> const double PI = 3.14159265358979; double perimetre( const double r ) { return 2 * PI * r; } double surface( const double r ) { return PI * r * r; } int main() { double rayon; cout << "Quel rayon ? "; cin >> rayon; cout << "perimetre=" << perimetre( rayon ) << endl; cout << "surface=" << surface( rayon ) << endl; return 0; }

Nous verrons au chapitre suivant qu'il est souvent nécessaire de déclarer de nouveaux types en global car ils servent à la fois dans le programme principal et dans les sous-programmes. Dans le cas de variables, il est fortement déconseillé -sauf cas très particuliers, voire exceptionnels- de profiter de cet effet de visibilité. Les variables globales doivent dans la mesure du possible être bannies. Remarque : il n'est pas possible (contrairement à des langages comme Pascal ou Ada) d'imbriquer les sous-programmes, c'est-à-dire de définir un sous-programme localement à un autre sous-programme.

7.9 Notion de ``prototype''
Il s'agit d'une déclaration se limitant à l'entête d'un sous-programme. Indispensables dans le cas d'utilisation de sous-programmes définis dans des fichiers compilés séparément, ainsi que pour des sousprogrammes s'appelant mutuellement, les prototypes peuvent également être utilisés pour améliorer la lisibilité des programmes. En introduisant au début les prototypes de toutes les fonctions et procédures définies par la suite, on donne en effet au lecteur une vue synthétique d'un ensemble de définitions de sous-programmes. De plus, lorsque des prototypes ont été introduits, les définitions effectives peuvent se faire dans un

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 36 of 63

ordre quelconque. Exemple 12
#include<iostream.h> /* DECLARATION DE FONCTION (PROTOTYPE) : */ double Puissance(const double x, const int n); /* x a la puissance n */ /* PROGRAMME PRINCIPAL : */ int main() { cout << Puissance(2.0, 10) << endl;

return 0;

}

/* DEFINITION DE FONCTION : */ double Puissance(const double x, const int n) { int i; double r; r = 1; for(i = 0; i < n; i++) r = r * x; return r; }

7.10 Quand créer des sous-programmes ?
Pour modulariser le programme. Si une même suite d'instructions utilisant les mêmes données doit être écrite plusieurs fois (``factorisation'' du code). Si une même suite d'instructions utilisant des données différentes doit être écrite plusieurs fois (outil paramétré). Si un traitement présente un intérêt général (outil réutilisable).

7.11 Recommandations
Un sous-programme doit obéir aux règles suivantes: [modularité:] un sous-programme réalise une tâche et une seule (par exemple, une fonction de calcul ne doit pas afficher de résultat) ; [autonomie:] un sous-programme est autonome et ne doit pas lire ni modifier directement les variables du programme qui l'appelle, sans passer par des paramètres ; [transparence:] un sous-programme doit être conçu de façon à ce que le programmeur qui y fait appel (non nécessairement son concepteur) n'ait pas à tenir compte des choix du concepteur ; [convivialité:] l'appel (l'utilisation) du sous-programme doit être la plus évidente possible.

8 Définition de nouveaux types de données
Nous avons jusqu'à présent utilisé uniquement des données de type standard : int, double, char . Ces types de données modélisent des ensembles bien connus de nombres ou de symboles. Mais si une résistance électrique peut être modélisée par un double, ou la taille d'une mémoire par un int, comment modéliser dans un programme des objets plus complexes, comme une liste de noms, un ensemble d'ensembles, une matrice, un fichier de bulletins de paie ? Pour cela, le programmeur doit définir de nouveaux types de données, simples ou structurés. Nous allons d'abord nous intéresser à la définition de types simples définis par synonymie ou énumération, et dans les chapitres suivants nous étudierons deux types structurés particulièrement importants : les tableaux et les structures hétérogènes.

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 37 of 63

8.1 Type défini par synonymie
Pour plus de clarté, il est possible de donner un nouveau nom à un type existant. Exemple 1 Après avoir écrit typedef double Reel; il est possible d'utiliser partout le type Reel à la place du type double, moins explicite. D'autre part, il est également possible de définir des nouveaux types à partir des modificateurs permis par le langage. Exemple 2 Pour définir la notion d'entier naturel, il suffit décrire :
typedef unsigned int Naturel;

8.2 Type défini par énumération
Supposez que vous deviez écrire un programme pour un distributeur automatique de jus de fruits. L'ensemble des fruits n'est pas un type prédéfini de C, comment faire ? Une solution serait de décider d'un codage arbitraire des fruits par des entiers : orange = 1, citron = 2, etc. L'inconvénient est de contraindre le programmeur à rappeler par des commentaires la signification de chacun de ces codes, faute de quoi le programme deviendrait illisible. De plus, le compilateur ne pourra faire aucune vérification quant à l'emploi de ces valeurs. Il sera donc possible d'exécuter, sans que cela soit sanctionné au niveau de la compilation, des instructions absurdes, comme l'addition d'un fruit et d'une somme d'argent. C (ainsi que C++, Pascal, ADA, etc., mais pas Java) autorise la définition du type ``fruits'', par simple énumération des fruits qui nous intéressent : Exemple 3
typedef enum {Orange, Citron, Pamplemousse, Tomate} Fruit; /* definition de variables de type Fruit : */ Fruit F1, F2;

La forme générale d'une définition de type énuméré est la suivante :
typedef enum { ENUMERATION DES ELEMENTS } NOMTYPE;

8.2.1 Valeur des éléments Les éléments d'un type énuméré sont représentés, en machine, par des entiers. Par défaut, le premier élément de la liste est codé par l'entier 0, le second par l'entier 1, etc. Exemple 4
/* si le type bool n'existait pas (utile en C) */ typedef enum {false, true} bool; /* false = 0 true = 1 */

Il est possible de choisir soi-même sa représentation interne en spécifiant les valeurs entières associées

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 38 of 63

(qui doivent être données en ordre strictement croissant) à chaque élément : Exemple 5
typedef enum {ARRIERE = -1, ARRET = 0, AVANT = 1} Mouvement;

8.2.2 Opérations sur une variable de type énuméré L'affectation d'une variable de type énuméré se fait selon les règles habituelles. Il est également possible de comparer des valeurs de type énuméré, d'incrémenter, de décrémenter une variable de type énuméré. Ces opérations portent en fait sur la représentation interne des symboles énumérés. Si l'on affiche une valeur définie par énumération, c'est l'entier correspondant (la représentation interne du symbole) qui sera affichée. Exemple 6
#include <iostream.h> int main() { typedef enum {Orange, Citron, Pamplemousse, Tomate} Fruit; Fruit Intrus; int I; Intrus = Tomate; cout << " Les agrumes sont : " << endl; for (I = (int)Orange; I <= (int)Pamplemousse; I++) cout << (Fruit)I << endl; /* meme effet avec cout << I << endl; */ cout << " L'intrus est : " << endl; cout << Intrus << endl; return 0; }

Exemple 7
#include <iostream.h> typedef enum { Cadillac, Rolls_Royce, Maserati, Toyota } Marque; void Appreciation(const Marque Auto) { switch (Auto) { case Cadillac: cout << "voyant" << endl; break; case Rolls_Royce: cout << "confortable" << endl; break; case Maserati: cout << "esthetique" << endl; break; case Toyota: cout << "pas cher" << endl; break; } /* switch */ }

Remarque : Avec ce type de déclaration (non Orientée Objet), on ne peut pas avoir le même élément dans 2 types énumérés différents.

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 39 of 63

Exemple 8
typedef enum { Orange , Citron, Pamplemousse, Tomate} Fruit; typedef enum {Bleu, Vert, Rouge, Orange } Couleur; /* INTERDIT !!! */

8.2.3 Vérifications de type à la compilation Un des rôles du compilateur, et non des moindres, est de détecter autant que possible les erreurs, et d'aider le programmeur en les lui signalant. Ainsi, dans toute expression, affectation ou appel de sousprogramme, il vérifie la cohérence entre les types des objets employés. Définir des types différents pour modéliser des classes d'objets différentes, c'est donner au compilateur l'information nécessaire pour ce travail de détection d'erreurs. Exemple 9
#include <iostream.h> int main() { typedef enum Surface {Carre, Rectangle, Triangle, Disque}; typedef enum Volume {Cube, Parallelepipede, Pyramide, Sphere}; Volume Vol; Surface Sur; Sur = Disque; Vol = Disque; return 0; } /* /* cette affectation est correcte */ ERREUR de type detectable par le compilateur */

9 Types structurés : tableaux
9.1 Définition
Un tableau est une collection ordonnée2 d'objets, en nombre fini et de même nature . On peut ainsi concevoir des tableaux d'entiers, de flottants, de caractères, mais aussi des tableaux de tableaux (tableaux à plusieurs dimensions) ou des tableaux contenant d'autres objets définis par le programmeur. Chaque élément d'un tableau est repéré par sa position ou indice (qui est un nombre entier). Il est possible grâce à cet indice d'aller modifier ou consulter n'importe quel élément d'un tableau. En C et en C++, l'indice du premier élément d'un tableau est toujours 0. La forme générale d'une définition de type tableau est la suivante :
typedef

TYPE_DES_COMPOSANTES NOM_DU_TYPE [NOMBRE_D_ELEMENTS];

Exemple 1
#include <iostream.h> int main() {

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 40 of 63

const int NbElements = 10; typedef int TypeTableau[NbElements]; /* definit le type: tableau de 10 entiers int I; TypeTableau UnTableau; /* definit une variable de type TypeTableau */

*/ */

for (I = 0; I < NbElements; I++) UnTableau[I] = 0; /* range la valeur 0 dans toutes les "cases" du tableau for (I = 0; I < NbElements; I++) if (UnTableau[I] != 0) cout << "il y a un bug!" << endl; /* teste si tous les elements sont bien a 0 return 0; }

*/

Remarque : le nombre d'éléments est défini à partir de constantes . On ne peut donc pas définir ainsi un type de tableau dont la dimension varie au cours de l'exécution du programme.

9.2 Type des composantes
Les composantes d'un tableau peuvent être de n'importe quel type (standard ou défini par le programmeur). Exemple 2
/* definit le type Mot: tableau de 20 caracteres */ typedef char Mot[20]; /* definit le type ListeFruits: tableau de 10 Fruits */ const int NombreFruits = 10; typedef enum {Orange, Citron, Pamplemousse, Tomate} Fruit; typedef Fruit ListeFruits[NombreFruits];

9.3 Tableau à 2 dimensions
L'exemple 9.1 montrait un type de tableau à une dimension (un vecteur). Un tableau à deux dimensions peut se concevoir comme un tableau d'objets de type vecteur : Exemple 3
const int NbLignes = 3; const int NbColonnes = 3; typedef double VecteurLigne[NbColonnes]; typedef VecteurLigne Matrice[NbLignes];

Mais d'autres formulations sont possibles, pour un résultat équivalent : Exemple 4
const int NbLignes = 3; const int NbColonnes = 3; typedef double Matrice[NbLignes][NbColonnes];

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 41 of 63

9.4 Tableau multidimensionels
Selon le même principe, on peut concevoir des tableaux à N dimensions. L'exemple suivant définit et commente les déclarations de types et de variables nécessaires pour stocker en mémoire une séquence de 25 images, chaque image étant composée de trois plans correspondant aux composantes rouge, verte et bleue, et chaque plan comportant 600 lignes de 800 pixels : Exemple 5

typedef int Sequence[25][3][600][800]; Sequence s1, s2;

OU (beaucoup mieux) :
const int NBCOLONNES = 800; const int NBLIGNES = 600; const int NBCOULEURS = 3; const int NBIMAGES = 25; typedef int Pixel; typedef Pixel Ligne[NBCOLONNES]; typedef Ligne Plan[NBLIGNES]; typedef Plan Image[NBCOULEURS]; typedef Image Sequence[NBIMAGES]; Sequence s1, s2;

C++
s1 s1[24] s1[24][0] s1[24][0][300] s1[24][0][300][10]

type
Sequence Image Plan Ligne Pixel

Commentaire Séquence s1 25ème image de s1 plan Rouge de la 25ème image de s1 301ème ligne du plan Rouge de la … 11ème pixel de la 301ème ligne du …

9.5 Tableaux et paramètres
En C comme en C++, le passage d'un tableau en paramètre de sous-programme est toujours effectué par adresse, jamais par valeur. En résumé : valeur (entrée) référence (sortie ou mixte) int (idem double, char …) tableau
const int x const TypTab t int & x TypTab t

Remarque : Nous verrons au chapitre 11.8 p.pageref que le passage d'un tableau en entrée ne se fait pas vraiment par valeur puisque toutes les valeurs du tableau ne sont pas recopiées à cette occasion.

9.6 Référence à un élément du tableau
Soit une variable Tab de type TypeTableau définie par :

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 42 of 63

const int NbElements = 100; typedef int TypeTableau[NbElements]; TypeTableau Tab;

Pour faire référence, par exemple, au 13ème élément de TAB, on écrit :
Tab[12]

car la numérotation des éléments d'un tableau commence à 0. Le premier élément d'un tableau est donc toujours Tab[0] . La syntaxe reste la même, qu'il s'agisse de modifier ou de lire le contenu de l'élément. Il est possible d'employer une expression quelconque pour désigner l'indice de l'élément à accéder : Exemple 6
const int NbElem = 8; typedef double Vecteur[NbElem]; void ExempleAcces(Vecteur V) { int J; J = NbElem - 1; /* indice du dernier element */ V[ J ] = 0.0; V[ J - 1 ] = V[ J ]; V[ (J + 1) / 2 ] = V[ J - 1 ]; /* . . . */ }

Pour les tableaux à plusieurs dimensions, il faut spécifier autant de valeurs d'indice que le tableau comporte de dimensions. Ainsi, un élément de matrice est repéré par un indice de ligne et un indice de colonne (I et J dans l'exemple suivant) : Exemple 7
const int NbLignes = 3; const int NbColonnes = 3; typedef double Matrice[NbLignes][NbColonnes]; void ExempleAccesMatrice(Matrice M) { int I, J; I = 0; J = 0; M[ I ][ J ] = 1; /* . . . */ }

9.7 Tableaux de caractères
Le type ``tableau de caractères'' est très utilisé pour représenter les textes, mots et chaînes de caractères manipulées dans les programmes.

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 43 of 63

Dans ce type d'application, il est courant de réserver un tableau de taille suffisante, pour pouvoir y ranger lors de l'exécution des chaînes de caractères de longueurs diverses. Pour indiquer la fin d'une chaîne de caractères, on emploie le caractère nul, celui dont le code ASCII est 0, et que l'on désigne par '\0' . Note : pour les chaînes de caractères constantes (entre guillemets), le caractère nul final est rajouté automatiquement par le compilateur. Une bibliothèque nommée string contient des fonctions et procédures usuelles de manipulation de chaînes de caractères. Pour les utiliser dans un programme, il faut placer dans l'entête la directive :
#include <string.h>

On peut par exemple utiliser le sous-programme strcpy (string copy ) pour initialiser une variable de type chaîne de caractères : Exemple 8
#include <iostream.h> #include <string.h> int main() { const int TAILLE = 10; typedef char Chaine[TAILLE]; Chaine Mot; strcpy(Mot, "ok"); cout << Mot << endl; return 0; } /* resultat: ok */

La bibliothèque string contient d'autres fonctions très utiles pour manipuler des chaînes de caractères : strlen (retourne la longueur d'une chaîne), strcmp (compare deux chaînes), strcat (ajoute une chaîne à la fin d'une autre chaîne), etc.

9.8 Lecture / écriture de tableaux
9.8.1 Tableaux numériques Il faut effectuer un ordre de lecture ou d'écriture pour chaque composante du tableau : Exemple 9
#include <iostream.h> const int TAILLE = 3; typedef double Matrice[TAILLE][TAILLE]; void AcquisMatrice(Matrice M) { int I, J; /* acquisition des coefficients d'une matrice 3 x 3 */ for (I = 0; I < 3; I++) { for (J = 0; J < 3; J++) {

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 44 of 63

cout << "M[" << I << "," << J << "] ?"; cin >> M[I][J]; } } /* . . . */ }

9.8.2 Tableaux de caractères Le cas des tableaux de caractères est particulier, il est possible de lire ou d'afficher leur contenu par un seul ordre : Exemple 10
#include <iostream.h> const int TailleChaine = 128; typedef char Chaine[TailleChaine]; void SaisieMot(Chaine Mot) { Mot[0] = '\0'; while (Mot[0] != 'q') { cin.getline(Mot, TailleChaine); cout << Mot << endl; } }

Notez la syntaxe particulière cin.getline(...) qui offre l'avantage ici de préciser le nombre maximum de caractères à lire dans le flux d'entrée. Si l'utilisateur du programme tape au clavier (strictement) moins de TailleChaine caractères avant le caractère de validation (\n), ceux-ci seront rangés dans le tableau Mot et un caractère nul (\0) sera introduit dans le tableau à la suite du dernier caractère saisi. Si l'utilisateur du programme tape au clavier plus de TailleChaine - 1 caractères avant le caractère de validation (\n), les caractères en ``trop'' seront conservés dans le tampon d'entrée jusqu'au prochain appel à cin. Si l'utilisateur du programme tape au clavier exactement TailleChaine - 1 caractères, le programme ne s'arrêtera pas sur la prochaine instruction getline car il considèrera le caractère \n de la première saisie comme une chaîne vide. Pour éviter cet inconvénient, il faut ajouter l'instruction cin.sync(); après chaque getline, ce qui vide le buffer avant la prochaine saisie.

9.9 Dangers des tableaux
Les langages C et C++ sont très permissifs et, hélas, ne contrôlent pas que toute instruction accède bien à une case autorisée dans un tableau. Par exemple, a = t[-1]; ou a = t[10]; pour un tableau t de 10 cases sont deux instructions autorisées, alors qu'elles accèdent à la case précédant (respectivement suivant) les 10 cases réservées pour le tableau t. Ces instructions ont apparemment peu de conséquences. En fait, la plupart du temps, le programme donne certains résultats faux, ce qui est d'autant plus dangereux qu'il est possible de ne pas s'en

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 45 of 63

apercevoir. Par contre, une instruction du type t[-1] = n; fait presque toujours ``planter'' le programme car elle peut écraser n'importe qu'elle donnée, mais aussi des instructions, ce qui donne un comportement du programme complètement imprévisible avant le ``plantage''. Ceci est la cause d'erreur la plus longue et la plus difficile à découvrir, notamment car le plantage du programme ne survient pas à l'endroit où se situe l'erreur, mais plus tard, selon ce qui a été écrasé. D'autre part, le simple fait d'ajouter un affichage pour déboguer, modifie le comportement du programme, et celui-ci se plante à un autre endroit, voire ne se plante plus ! Il est donc impératif de bien vérifier tous les indices (notamment dans les boucles), ainsi que les tailles de tableau (notamment dans les entrées/sorties de chaînes de caractères). Après avoir passé une journée entière à essayer de trouver où se situe le dépassement d'indice, il peut être utile de lire la page : http://www.esiee.fr/~bureaud/fi/unites../debugtab.html . Y est décrit une méthode qui, moyennant la modification de toutes les déclarations de tableaux, permet généralement de trouver la cause de l'erreur. Une fois l'erreur corrigée, il est ensuite possible, soit de désactiver l'ensemble du système de détection d'erreur par un simple #define, soit de re-modifier toutes les déclarations pour qu'elles retrouvent leur forme habituelle. Cette méthode peut paraître lourde, mais elle ne prend que quelques minutes, alors que la recherche de telles erreurs dans un programme de plusieurs centaines de lignes peut prendre plusieurs jours ...

9.10 Exercices
9.10.1 Tableaux de dimension 1 Exercice 1 Écrire un programme qui lit huit entiers et qui les affiche dans l'ordre inverse de l'ordre d'entrée. On utilisera une boucle pour la lecture et une autre boucle pour l'écriture. Exercice 2 Écrire un sous-programme qui incrémente d'une unité les éléments d'un tableau de huit entiers. Exercice 3 Écrire un sous-programme qui inverse les huit éléments d'un tableau. On utilisera une seule boucle. Exercice 4 Écrire un sous-programme qui calcule la somme des éléments d'un tableau de huit entiers. Exercice 5 Écrire un sous-programme qui détermine la plus grande et la plus petite valeur d'un tableau de huit entiers. On utilisera une seule boucle. Exercice 6 Écrire un programme qui compte les fréquences (le nombre d'occurences) des caractères entrés par l'utilisateur. Exercice 7 Un palindrome est un mot ou une phrase qui se lit indifféremment de gauche à droite ou de droite à gauche ; par exemple, sont des palindromes :
ARA KAYAK QSDFGHHGFDSQ ELU PAR CETTE CRAPULE

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 46 of 63

ESOPE RESTE ICI ET SE REPOSE

Écrire un sous-programme qui vérifie si un mot ou une phrase est un palindrome. Exercice 8 Écrire un algorithme qui détermine, par la méthode du crible d'Ératosthène, les nombres premiers parmi les 10000 premiers entiers naturels. Le principe de la méthode est de ``marquer'' successivement les multiples de 2, 3, … qui ne sont donc pas premiers. A la fin (comment la determiner ?), les nombres non marqués sont premiers. Exemple, avec décisions à chaque étape (V pour ``est premier'', F pour ``n'est pas premier'') :
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ... v f f f f f f f f f f f v f f f f f f f v f f f f v f f

9.10.2 Tableaux à plusieurs dimensions Exercice 9 Écrire un programme qui affiche les dix premières lignes du triangle de Pascal. (Rappel : le triangle de Pascal regroupe les coefficients binomiaux Cnp, et se construit facilement grâce à la

relation : Cnp = Cn−1p−1 + Cn−1p)

10 Types structurés : structures hétérogènes (struct)
Nous avons étudié dans le paragraphe précédent le type tableau . Dans un tableau, tous les éléments sont de même type. La structure hétérogène (struct) permet de regrouper des éléments hétérogènes, c'est-à-dire de types différents. Cette structure permet en outre de nommer chacune de ses composantes, contrairement au tableau dans lequel chaque élément est repéré par un indice . Considérons par exemple un logiciel de gestion de stock pour une épicerie. Pour chaque article, on tient à jour les informations suivantes : la désignation de l'article le prix unitaire la quantité disponible la date à laquelle le lot est périmé le délai nécessaire au réapprovisionnement Manifestement, toutes ces informations ne sont pas de type simple. La désignation (le nom de l'article) est une chaîne de caractères, et nécessite donc une définition du type :
const int MaxNom = 80; typedef char TypNom[MaxNom];

De même, la date de péremption de l'article peut être représentée par une chaîne de la forme ``01/12/92'',

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 47 of 63

et donc être définie par :
typedef char TypDate1 [9]; /* 9 = 8 pour la date + 1 pour le \0 */

mais cette représentation rend difficile la comparaison de dates. On peut donc lui préférer la représentation suivante, sous forme de structure, en utilisant le constructeur struct :
typedef struct { int Jour; int Mois; int Annee; } TypDate;

Nous pouvons désormais définir la structure de donnée ``Article'', elle aussi construite à partir de types standard ou définis préalablement, à l'aide du constructeur struct.
typedef struct { TypNom Nom; double PrixUnitaire; int Disponible; TypDate DatePeremption; int DelaiReapp; } Article;

Une composante d'une structure est aussi appelée un champ .

10.1 Définition
La forme générale d'une définition de type struct est la suivante :
typedef struct {

TypeChamp1 NomChamp1; TypeChamp2 NomChamp2; … TypeChampN NomChampN;
}

NOM_DU_TYPE;

10.2 Accès aux composantes
Grâce aux définitions ci-dessus, définissons une variable de type ``Article'' :
Article A1;

Pour faire référence (en lecture comme en écriture) au prix unitaire de cet article, on écrira :
A1.PrixUnitaire

La forme générale d'un accès à une composante de structure est :

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 48 of 63

Structure.NomComposante

Cette notation s'étend naturellement au cas des structures emboîtées. Ainsi pour désigner le mois de péremption d'un article a1, on écrira :
A1.DatePeremption.Mois

Voici, pour illustrer la notion d'enregistrement, la définition d'une fonction permettant de comparer deux dates (de type TypDate) : Exemple 1
/* cette fonction renvoie true si la date d1 <= d2, false sinon */ bool Precede(const TypDate D1, const TypDate D2) { bool res; if (D1.Annee < D2.Annee) res = true; else if (D1.Annee > D2.Annee) res = false; else /* d1.Annee == d2.Annee */ if (D1.Mois < D2.Mois) res = true; else if (D1.Mois > D2.Mois) res = false; else /* D1.Mois == D2.Mois */ if (D1.Jour <= D2.Jour) res = true; else /* d1.Jour > d2.Jour */ res = false; return res; }

10.3 Passage d'une structure en paramètre
Les règles sont les mêmes que pour les types de base (passage par valeur avec const, ou par adresse avec &). Exercice 1 Écrire en C++ les déclarations nécessaires pour représenter une personne dans un agenda personnel, avec notamment son nom, son prénom, son adresse (rue, code postal, ville), son numéro de téléphone, etc. Exercice 2 Écrire une fonction qui calcule la différence en heures, minutes, secondes, entre deux temps exprimés en heures, minutes, secondes.

11 Pointeurs
11.1 Définition d'un type pointeur
Nous avons vu que les objets manipulés dans les programmes sous forme de variables, qu'ils soient de type simple (int, double ...) ou composé (tableau, structure) correspondent à des emplacements réservés dans la mémoire de l'ordinateur. La mémoire centrale des ordinateurs que nous utilisons (stations de travail, PC…) est découpée logiquement en octets (mots de 8 bits). Chacun de ces octets est numéroté, autrement dit, il possède une adresse unique, un nombre entier qui sert à l'identifier. Chaque octet de mémoire peut stocker une donnée de type caractère (char). Pour d'autres types de données comme les entiers, plusieurs octets consécutifs doivent être utilisés (les entiers de type int, dans notre environnement de programmation, sont stockés sur quatre octets). L'adresse de la zone de

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 49 of 63

mémoire correspondant à un objet de type entier est par convention l'adresse du premier octet, dans l'ordre des adresses croissantes, de cette zone. Pour manipuler les adresses, nous avons besoin d'un nouveau type de données : le type pointeur . En fait, un pointeur est simplement une adresse, donc un entier ; mais pour des raisons de sécurité, on prend soin de distinguer pointeurs et entiers (un pointeur n'est donc pas un int), ainsi que les différents types de pointeurs entre eux. Ainsi, un pointeur de flottant en double précision (adresse d'un objet de type double) et un pointeur de caractère (adresse d'un objet de type char) sont de types différents.
double

Voici, en C++, la définition du type ``pointeur de flottant'', autrement dit, adresse d'un objet de type :

Exemple 1
typedef double *PtrDouble; /* declaration de type */

11.2 Variables de type pointeur
Puisque nous connaissons un nouveau type de données, il est naturel de pouvoir déclarer des variables de ce type, c'est-à-dire des variables pour stocker des pointeurs (ou adresses) : Exemple 2
PtrDouble P1, P2; /* declaration de variables */

Dans cet exemple, P1 et P2 sont donc des variables susceptibles de recevoir des adresses de flottants (double). Par abus de langage, on appelle souvent pointeur une telle variable, alors qu'il vaudrait mieux réserver cette appellation à l'adresse contenue dans cette variable. Vous trouverez dans de nombreux programmes des définitions de variables de type pointeur non précédées de la définition du type pointeur correspondant. Cela peut alléger l'écriture dans le cas de pointeurs sur des objets de type simple (int, char, double, …) mais cette pratique est déconseillée s'il s'agit d'objets structurés. Exemple 3
double *P1, *P2; /* declaration de variables */

Attention : si vous déclarez simultanément plusieurs variables de type pointeur, comme dans l'exemple ci-dessus, le signe * doit précéder chaque nom de variable.

11.3 Valeurs de pointeurs - l'opérateur &
Soit V une variable (par exemple de type entier), nous pouvons récupérer son adresse grâce à l'opérateur & ; l'expression &V désigne en effet cette adresse. Exemple 4
int main() { typedef int *PtrEntier; PtrEntier Pe int Entier;

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 50 of 63

Pe = &Entier; return 0; }

11.4 Accès à l'objet ``pointé'' - l'opérateur *
La connaissance de l'adresse d'un objet nous permet d'accéder au contenu (à la valeur) de cet objet, par l'usage de l'opérateur * : Exemple 5
#include <iostream.h> int main() { typedef int * PtrEntier; PtrEntier Pe; int Entier; Entier = 17; Pe = &Entier; /* Pe contient l'adresse de la variable Entier */ cout << "Entier contient: " << *Pe << endl; /* affiche 17 */ *Pe = *Pe + 1; /* incremente la valeur contenue dans Entier */ cout << "Entier contient: " << Entier << endl; /* affiche 18 */ return 0; }

Remarques : Si V est une variable convenablement déclarée, alors les expressions *&V et V sont équivalentes. Ne confondez pas l'opérateur * (accès à l'objet pointé) avec l'opérateur * (multiplication). Le contexte permet de les distinguer. De même, ne confondez pas l'opérateur & (accès à l'adresse d'un objet) avec l'opérateur & (passage de paramètre par adresse). Attention : Une erreur courante consiste à utiliser *Pe avant que la variable Pe n'ait été initialisée. La variable Pe peut alors contenir une adresse quelconque ; le comportement du programme n'est donc pas prévisible (plantage, résultats incohérents, etc).

11.5 Pointeur NULL
Le pointeur NULL est une adresse fictive ne correspondant à aucune zone de mémoire accessible. Dans la plupart des systèmes, il vaut 0. C'est une constante définie notamment dans le fichier iostream.h . Il est utilisé pour signaler une erreur lors de l'emploi d'une fonction devant retourner un pointeur, ou pour symboliser un ``objet vide'' dans le cas d'objets complexes chaînés au moyen de pointeurs (voir section 11.10 ).

11.6 Allocation de mémoire - l'opérateur new
Il me paraît indispensable de faire ici quelques remarques importantes, en ce sens qu'elles vous permettront (peut-être) d'éviter des erreurs douloureuses, ou du moins de les corriger plus vite : déclarer une variable de type pointeur ne signifie en aucune façon réserver (allouer) de la mémoire

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 51 of 63

pour l'objet pointé ; immédiatement après la déclaration d'une variable (qu'elle soit de type pointeur ou autre), le contenu de celle-ci est inconnu ; pour utiliser l'opérateur * , il faut être absolument certain que la variable de type pointeur à laquelle on l'applique contient une adresse légale, c'est-à-dire l'adresse d'une zone mémoire effectivement allouée au stockage d'un objet. A quoi s'expose-t-on dans le cas contraire ? A une erreur lors de l'exécution du programme provoquant son arrêt complet et l'affichage d'un message du type bus error-core dumped ou segmentation fault. Comment allouer de la mémoire ? C'est ce que nous allons voir tout de suite. La première façon d'allouer de la place mémoire pour y stocker des objets vous est déjà connue : c'est la déclaration de variables. Les adresses de ces objets peuvent alors être récupérées grâce à l'opérateur & déjà présenté. La seconde façon, dite allocation dynamique, consiste à faire exécuter dans le programme une opération d'allocation nommée new qui retourne comme résultat : une adresse légale si tout s'est passé correctement, NULL dans le cas contraire (par exemple si toute la mémoire de l'ordinateur est déjà occupée). L'opérateur new prend pour opérande droit le type de l'objet à allouer, ce qui définit la taille de la zone de mémoire à réserver pour stocker cet objet. Exemple 6
#include <iostream.h> int main() { typedef int * PtrEntier; PtrEntier Pe; Pe = new int; if (Pe == NULL) cout << "allocation d'un entier ratee" << endl; else { cout << "allocation d'un entier reussie" << endl; /* REMARQUE : a ce niveau, la place memoire reservee a un contenu indetermine. Pour y stocker une valeur il faut executer, par exemple: */ *Pe = 13; } return 0; }

L'avantage de l'allocation dynamique par rapport à la déclaration de variables est de permettre d'adapter, lors de l'exécution du programme, la consommation de mémoire à la taille effective des données traitées. Pour déclarer une variable de type tableau, on a vu que la dimension du tableau devait être spécifiée par

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 52 of 63

une constante. La seule façon d'allouer un tableau dont on ne connaît pas à l'avance la dimension est donc l'allocation dynamique. L'allocation dynamique de tableau peut se faire simplement par l'opération :
pointeur_type_objet = new nom_type_objet[taille_tableau];

La section 11.8 précise les rapports existant entre pointeurs et tableaux.

11.7 Libération de mémoire - l'opérateur delete
Lorsqu'une zone mémoire allouée dynamiquement (par new) n'est plus utilisée par le programme, il est possible, et même souvent souhaitable, de la libérer, c'est-à-dire de la rendre à nouveau disponible pour d'autres utilisations, grâce à l'opérateur delete : Exemple 7
int main() { typedef int * PtrEntier; PtrEntier Pe; Pe = new int; /* ... */ delete Pe; return 0; }

Attention : pour utiliser l'opérateur delete, il faut être certain que l'opérande pointe effectivement sur un objet alloué grâce à l'opérateur new .
delete

La libération de la mémoire occupée par un tableau alloué dynamiquement s'effectue par un seul :

Exemple 8
int main() { int taille; typedef int * PtrEntier; PtrEntier Pe; cout << "Quelle taille ? "; cin >> taille; Pe = new int[taille]; // taille est une variable ! /* ... */ delete Pe; return 0; } /* libere en une fois le tableau */

Exercice 1 Écrire une fonction qui calcule le plus grand nombre premier inférieur ou égal à un entier N donné, par la méthode suivante :

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 53 of 63

alloue un tableau dynamique de booléens de taille N, applique la methode du crible d'Eratosthène (exercice 9.8 ), recherche le plus grand nombre premier, libère la place occupée par le tableau avant de retourner le résultat.

11.8 Pointeurs et tableaux
Les noms de variables de type tableau ont un statut particulier en C++ : ils représentent l'adresse du premier élément du tableau, et ce sans qu'il soit besoin d'avoir recours à l'opérateur & . Remarque : on peut déduire de ce qui précède que les expressions Mot (dans l'exemple ci-dessous) et & (Mot[0]) sont équivalentes. Il est donc possible d'utiliser le nom d'une variable de type tableau exactement comme une constante de type pointeur , comme le montre l'exemple suivant : Exemple 9
const int TailleChaineCar = 80; typedef char ChaineCar[TailleChaineCar]; void Change_aA(ChaineCar Mot) { typedef char *PtrChar; PtrChar P; P = Mot; while (*P != '\0') { if (*P == 'a') *P = 'A'; P++; } } /* utilise l'equivalence tableau - pointeur */

/* change les a minuscules en A majuscules */

Il est important de préciser que l'incrémentation ou la décrémentation d'une variable de type pointeur (P++, P=P-2, etc) n'agit pas sur le pointeur en qualité de nombre entier (une adresse est en effet, somme toute, un nombre entier), mais bien en sa qualité d'adresse d'un objet possédant une taille précisée par son type . Par exemple, incrémenter d'une unité une variable de type pointeur de flottant conduit à rajouter à l'adresse contenue dans la variable le nombre d'octets composant un flottant (huit pour le type double dans notre environnement). Cette opération peut donc être vue logiquement comme le ``passage au flottant suivant''. Autre exemple : si le pointeur P est un pointeur de flottant et contient l'adresse 197568, après l'exécution de l'instruction P = P - 2; P contiendra l'adresse 197552. Note : dans l'exemple précédent, le paramètre Mot ne doit pas, logiquement, être passé par référence, car il représente l'adresse du premier élément du tableau ; or cette adresse ne doit pas être modifiée par la fonction.

11.9 Pointeurs et structures
Il est possible, avec les opérateurs et les constructions que nous venons d'étudier, de définir et de manipuler des pointeurs de type structure (struct), en allouant les structures soit dynamiquement, soit sous forme de variables.

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 54 of 63

Voici un exemple simple : Exemple 10
typedef struct { double Reel; double Imag; } Complexe; typedef Complexe *PtrComplexe; PtrComplexe AlloueComplexeNul() { PtrComplexe P; P = new Complexe; (*P).Reel = 0.0; (*P).Imag = 0.0; return P; }

Une notation spécifique permet de simplifier l'écriture de l'accès aux champs d'une structure pointée, simplification appréciable surtout dans le cas de structures possédant des champs pointant sur d'autres structures … :
(*P).Imag

est équivalent à : P->Imag est équivalent à : p->ptr1->ptr2

(*((*p).ptr1)).ptr2

etc.

11.10 Listes chaî nées
Une utilisation particulièrement intéressante des pointeurs associés aux structures est la définition de structures dites chaînées , dont l'exemple le plus simple est la liste chaînée. On pourra généraliser cet exemple aux arbres et aux graphes. L'idée est de réserver un champ dans chaque cellule de liste pour pointer sur la cellule suivante de la liste. Une liste peut ainsi être représentée uniquement par le pointeur sur sa première cellule. La liste vide, ou la fin de liste, sera représentée par le pointeur NULL. Voici les déclarations de type nécessaires à la définition d'une structure de liste de flottants en double précision (double) : Exemple 11
typedef struct TmpCellule { double Element; TmpCellule *Suivant; } Cellule; typedef Cellule *PtrCellule; typedef PtrCellule Liste;

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 55 of 63

Noter que pour désigner le type du champ Suivant, il est nécessaire de faire apparaître le nom ``provisoire'' de la structure (TmpCellule) au début de la définition, après le mot-clé struct. Noter également que, comme le type Cellule n'a pas à cet endroit reçu de définition complète, il faut dans la définition du champ Suivant employer la syntaxe :
nom_provisoire * nom_champ;

Il est également possible d'écrire : struct nom_provisoire * nom_champ; Le lecteur attentif aura certainement relevé la redondance des types PtrCellule et Liste, qui sont en effet strictement équivalents. Cette redondance est volontaire, elle permet d'améliorer la lisibilité en distinguant les pointeurs de cellule (utilisés pour pointer une cellule isolée ou une cellule particulière, par exemple lors d'une construction ou d'un parcours de liste) et les pointeurs de liste, qui, pointant effectivement sur la première cellule de la liste, permettent indirectement l'accès à la liste entière. Voici pour terminer un exemple simplifié de construction et d'affichage d'une liste composée de deux cellules. Il ne sera pas tenu compte de la possibilité d'erreur lors de l'allocation (voir exemple 11.6 ) ni de la libération de mémoire (voir section 11.7 ). Exemple 12
#include <iostream.h> typedef struct TmpCellule { double Element; TmpCellule *Suivant; } Cellule; typedef Cellule *PtrCellule; typedef PtrCellule Liste; Liste CreeListeExemple() { Liste L; PtrCellule Temp; L = NULL; /* liste vide */

/* ajout future 2eme cellule */ Temp = new Cellule; Temp->Element = 2.0; Temp->Suivant = L; L = Temp; /* ajout 1ere cellule en debut de liste */ Temp = new Cellule; Temp->Element = 1.0; Temp->Suivant = L; L = Temp; return L; } void AfficheListe(Liste L) { PtrCellule Temp; for (Temp = L; Temp != NULL; Temp = Temp->Suivant) cout << Temp->Element << endl; } int main()

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 56 of 63

{ AfficheListe(CreeListeExemple()); return 0; }

Remarques : 1. la liste créée dans cet exemple peut se représenter par le diagramme suivant :

Ce type de diagramme est très utilisé dans la littérature informatique pour visualiser les structures chaînées. 2. Toutefois une représentation plus exacte serait :

3. Enfin, certains préfèrent utiliser une première cellule "bidon" pour simplifier les traitements (la liste n'est jamais réduite au pointeur NULL). D'autres considèrent cette solution comme intellectuellement inacceptable car une cellule par liste est toujours allouée pour rien. Exercice 2 Écrire des fonctions informatives sur une liste qui répondent à des questions telles que : 1. 2. 3. 4. La liste est-elle vide ? Combien contient-elle de cellules ? Contient-elle une cellule avec telle valeur ? Combien de fois contient-elle une telle cellule ?

Exercice 3 Écrire des procédures d'insertion de cellule telles que : 1. 2. 3. 4. 5. 6. Ajouter au début, à la fin, avant ou après une certaine valeur, avant ou après la Nème cellule.

Exercice 4 Écrire des procédures de destruction de cellule telles que : 1. 2. 3. 4. 5. 6. Enlever la première, la dernière, ou la Nème cellule, enlever la première cellule qui contient telle valeur, ou toutes les cellules qui contiennent cette valeur, détruire toute la liste.

Exercice 5 Écrire des procédures de traitement global d'une liste telles que :

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 57 of 63

1. Afficher la liste, 2. trier la liste, 3. ou inverser l'ordre des cellules. Exercice 6 Écrire des procédures de manipulation de plusieurs listes telles que : 1. 2. 3. 4. Comparer deux listes, insérer une liste dans une autre, rechercher une liste dans une autre, enlever une liste d'une autre.

12 Fichiers de texte
Ce chapitre a pour but d'introduire les notions de base pour pouvoir lire et écrire des données simples dans des fichiers. Ces fichiers sont appelés ``fichiers de texte'' car ils sont éditables à l'aide d'un simple éditeur de texte. D'autre part, l'opération de lecture dans un fichier de texte est équivalente à celle de lecture au clavier ; de même, celle d'écriture dans un fichier de texte est équivalente à celle d'affichage à l'écran. Cela signifie que, sous réserve d'avoir au préalable déclaré une ``variable fichier'', il suffira de remplacer cin ou cout par cette variable.

12.1 Inclusion
Pour utiliser les fichiers en C++, il est nécessaire d'inclure le fichier <fstream.h> .

12.2 Déclaration (et ouverture)
Pour déclarer un fichier en lecture, on peut écrire : ifstream Var_fich( Nom_fich ); où Nom_fich est une chaine de caractères (constante littérale ou tableau de caractères) contenant le nom du fichier à ouvrir sur le disque, et où Var_fich est la ``variable fichier'' évoquée en introduction. Pour déclarer un fichier en écriture, on peut écrire : ofstream Var_fich( Nom_fich ); avec les mêmes conventions. Il est à noter qu'une telle déclaration provoque également l'ouverture du fichier, et qu'une instruction du type open() n'est donc pas nécessaire. Il est par contre possible de tester si l'ouverture s'est effectuée correctement par l'instruction suivante :
if ( Var_fich.fail() ) cout << "Je n'ai pas pu ouvrir ..." << endl;

Attention ! Pour obtenir le comportement décrit ci-dessus pour ifstream avec le compilateur MicroSoft Visual C++, il faut écrire :
ifstream Var_fich( Nom_fich, ios::nocreate );

12.3 Lecture
Exemple 1 Soit la déclaration : ifstream F_entree( "entiers.dat" ); en supposant que le fichier ëntiers.dat" existe bien.

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 58 of 63

Lire un caractère : char C; F_entree >> C; Lire deux entiers : int I, J; F_entree >> I >> J; Lire une chaine de caractères : const int MAX=80; char Tab[MAX]; Lire un mot : F_entree >> Tab; Lire une ligne : F_entree.getline( Tab, MAX ); Lorsqu'on lit successivement des lignes dans un fichier, il faut déterminer à quel moment s'arrêter pour ne pas aller au-delà de la fin de fichier. La boucle typique est : while ( ! F_entree.eof() ) ... (eof signifie end of file).

12.4 Écriture
Exemple 2 Soit la déclaration : ofstream F_sortie( "entiers.dat" ); Si le fichier ëntiers.dat" existe déjà, il est écrasé, sinon il est créé. Écrire un caractère : F_sortie << C; Écrire deux entiers : F_sortie << I << ' ' << J << endl; Écrire une chaine de caractères :
F_sortie << Tab; F_sortie << Tab << endl;

(⇒ prochaine écriture à la ligne suivante)

12.5 Fermeture
La fermeture d'un fichier s'effectue automatiquement à la sortie du bloc d'instructions { } dans lequel la ``variable fichier'' est déclarée. Toutefois, si pour verrouiller le fichier le moins longtemps possible vis à vis des autres utilisateurs il est souhaité une fermeture plus tôt, il est possible de l'effectuer par l'instruction : F_entree.close(); ou F_sortie.close(); .

12.6 Passage de paramètres
Les paramètres de type ifstream ou ofstream doivent obligatoirement être passés par référence. Exemple 3
#include <iostream.h> #include <fstream.h> const int MAX=80; typedef char Chaine[MAX]; void affiche( ifstream & ); int main() { Chaine nom; cout << "Quel fichier ? "; cin >> nom; ifstream fe( nom, ios::nocreate ); affiche( fe ); return 0; } // main() void affiche( ifstream & f ) {

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 59 of 63

Chaine tmp; while ( ! f.eof() ) { f.getline( tmp, MAX ); cout << tmp << endl; } } // affiche()

12.7 Conclusion
Ce chapitre n'a fait qu'effleurer les possibilités de traitement de fichiers, mais l'indispensable est là. De nombreuses autres fonctions sont disponibles pour accéder aux fichiers de texte, et d'autres sortes de fichiers (non visualisables par un éditeur de texte) existent également.

13 Du C++ au C-ANSI
Ce chapitre a pour but de vous montrer, au travers d'exemples simples, comment transformer en C-ANSI un programme écrit dans le sous-ensemble du C++ présenté dans ce document.

13.1 Entête
Remplacer #include <iostream.h> par #include <stdio.h>

13.2 Affichage
int : remplacer cout << I << ',' << J << endl; par printf( "%d,%d\n", I, J ); double : remplacer cout << D << endl; par printf( "%lf\n", D ); char[ ] : remplacer cout << mot << endl; par printf( "%s\n", mot );

13.3 Saisie
int : remplacer cin >> I >> J; par scanf( "%d %d", &I, &J ); double : remplacer cin >> D; par scanf( "%lf", &D ); char[ ] : remplacer cin >> mot; par scanf( "%s", mot ); char[ ] : remplacer cin.getline( ligne, taille ); par fgets( ligne, taille, stdin ); mais le '\n' est conservé !

13.4 Type de données logiques
Le type bool n'existe pas. Mais on peut le définir comme au paragraphe 8.2.1 .

13.5 Allocation dynamique
remplacer p = new int[10]; par p = (int *)malloc( 10 * sizeof(int) ); remplacer delete p; par free( p );

13.6 Passage de paramètre par adresse
(voir section 7.5 ).

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 60 of 63

Prenons l'exemple d'un programme C++ échangeant le contenu de deux variables : Exemple 1
#include <iostream.h> void Echange( int &A, int &B ) { int T; T = A; A = B; B = T; } int main() { int X, Y; X = 4; Y = 128; Echange( X, Y ); cout << "X=" << X << endl; /* affiche 128 */ cout << "Y=" << Y << endl; /* affiche 4 */ return 0; }

Et voici maintenant la version C de ce programme, utilisant des pointeurs pour produire rigoureusement le même effet que le programme précédent : Exemple 2
#include <stdio.h> void Echange( int *A, int *B ) /* des adresses d'entier seront passees explicitement en parametre */ { int T; T = *A; /* il faut acceder aux objets */ *A = *B; /* dont les adresses sont dans */ *B = T; /* les parametres A et B */ } int main() { int X, Y; X = 4; Y = 128; Echange( &X, &Y ); /* adresses des variables X et Y explicitement passees en parametres */ /* affiche 128 */ /* affiche 4 */

printf( "X=%d\n", X ); printf( "Y=%d\n", Y ); return 0; }

13.7 Fichiers de texte
Les exemples ci-dessous font référence au chapitre 12 . 13.7.1 Inclusion Il n'y a pas d'équivalent à <fstream.h> ; le fichier <stdio.h> suffit.

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 61 of 63

13.7.2 Déclaration (et ouverture) remplacer ifstream Var_fich( Nom_fich ); par FILE * Var_fich = fopen( Nom_fich, "r" ); (r comme read) remplacer ofstream Var_fich( Nom_fich ); par FILE * Var_fich = fopen( Nom_fich, "w" ); (w comme write) remplacer if ( Var_fich.fail() ) cout << "..." << endl; par
if ( ! Var_fich ) printf( "...\n" );

Il est à noter d'une part, qu'il est possible de déclarer Var_fich au début du programme, puis d'effectuer l'ouverture plus tard ; d'autre part, que le mot-clé FILE est une exception puisqu'il doit obligatoirement être écrit en majuscules. 13.7.3 Lecture Soit la déclaration FILE * F_entree; et l'ouverture F_entree = fopen( "entiers.dat", "r" ); . remplacer F_entree >> C; par C = fgetc( F_entree ); (ou par fscanf( F_entree, "%c", &C ); ) remplacer F_entree >> i >> j; par
fscanf( F_entree, "%d %d", &I, &J ); remplacer F_entree >> Tab; par fscanf( F_entree, "%s", Tab ); remplacer F_entree.getline( Tab, MAX ); par fgets( Tab, MAX, F_entree ); mais le '\n' est conservé ! remplacer while ( ! F_entree.eof() ) ... par while ( ! feof( F_entree ) ) ...

13.7.4 Écriture Soit la déclaration FILE * F_sortie; et l'ouverture F_sortie = fopen( "entiers.dat", "w" ); . remplacer F_sortie << C; par fputc( C, F_sortie ); (ou par fprintf( F_sortie, "%c", C ); ) remplacer F_sortie << i << ' ' << j << endl; par
fprintf( F_sortie, "%d %d\n", I, J ); remplacer F_sortie << Tab; par fputs( Tab, F_sortie ); (ou par fprintf( F_sortie, "%s", Tab ); ) remplacer F_sortie << Tab << endl; par fprintf( F_sortie, "%s\n", Tab );

13.7.5 Fermeture Elle n'est pas automatique. Remplacer F_entree.close(); et F_sortie.close(); par fclose ( F_entree ); et fclose( F_sortie ); .

14 Notions de logique booléenne
14.1 Valeurs possibles
Les deux seules valeurs possibles sont Vrai et Faux (ou bien V et F dans les tables de vérité, true et false en C++ et en Java, 1 et 0 en C, T et F en Fortran, etc...).

14.2 Opérateurs

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 62 of 63

Les opérateurs booléens habituels sont : NON, ET, OU. Les opérateurs de comparaison fournissent des valeurs booléennes. Exemple d'expression booléenne : NON ( 'a' <= carac ET carac <= 'z' )

14.3 Tables de vérité
A NON A ET V F OU V F V F V VF V VV F V F FF F VF (NON A) est vrai si et seulement si A est faux (NON A) est faux si et seulement si A est vrai (A ET B) est vrai si et seulement si A est vrai et B est vrai (A ET faux) est toujours faux (A OU B) est faux si et seulement si A est faux et B est faux (A OU vrai) est toujours vrai

14.4 Règles de simplification
1. 2. 3. 4. 5. 6. 7. NON( NON A ) → A A ET A → A A OU A → A NON( A ET B ) → (NON A) OU (NON B) NON( A OU B ) → (NON A) ET (NON B) NON( x < = y ) → ( x > y ) NON( x < y ) → ( x > = y )

14.5 Évaluation en C++
Voir notation section 2.4 . En C++, l'évaluation d'une expression booléenne s'effectue de gauche à droite, et s'arrête dès que la valeur de l'expression globale peut être déterminée. Exemples : ( e && false ) : e est évaluée, mais sa valeur est sans importance ( e || true ) : e est évaluée, mais sa valeur est sans importance ( false && e ) : e n'est jamais évaluée ( true || e ) : e n'est jamais évaluée Exercice 1 L'opérateur XOR n'existe pas en C++, mais il est utilisé en électronique. Il se traduit par OU exclusif et signifie ``soit l'un, soit l'autre, mais pas les deux'', par opposition au OU (inclusif) qui signifie ``soit l'un, soit l'autre, mais éventuellement les deux à la fois''. Écrivez la table de vérité de l'opérateur XOR. Il peut être créé par une combinaison d'opérateurs NON, ET, OU. Laquelle ? Exercice 2 L'opérateur NAND n'existe pas en C++, mais il est très utilisé dans les composants électroniques.

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008

INITIATION\\ A LA PROGRAMMATION STRUCTUR\'EE\\ AVEC LE LANGAG... Page 63 of 63

Il est très facile à créer puisque A NAND B = NON( A ET B ). Écrivez la table de vérité de l'opérateur NAND. Tous les opérateurs logiques peuvent être recrées à l'aide uniquement de combinaisons d'opérateurs NAND. 1. 2. 3. 4. A NAND A = ? (A NAND B) NAND (A NAND B) = ? (A NAND A) NAND (B NAND B) = ? (A NAND (B NAND B)) NAND ((A NAND A) NAND B) = ?

15 Bibliographie
``Le langage C'', Claude Delannoy, ed. Eyrolles. ``C++, guide complet'' ou ``Programmer en langage C++'' (à partir de la 2ème édition), Claude Delannoy, ed. Eyrolles. approche pédagogique ``Le langage C++'' (à partir de la 2ème édition), Bjarne Stroustrup, ed. Addison-Wesley. manuel de référence

Footnotes:
1American National 2l'ordre porte

Standard Institute

sur le rang des objets, non sur leur valeur

File translated from TEX by TTH, version 2.75. On 13 Sep 2002, 15:42.

http://www.esiee.fr/~bureaud/fi/Pempc/2002/polypro.html

10/04/2008


				
DOCUMENT INFO
Shared By:
Categories:
Stats:
views:31
posted:11/2/2009
language:French
pages:63