Vous êtes sur la page 1sur 66

EI1

Programmation
Équipe pédagogique

École Centrale de Nantes


École Centrale de Nantes, — Algorithmique et programmation — 2
Table des matières

1 Introduction 5

I PROGRAMMATION
C++ 6
2 Données et structures de données 8
2.1 Les données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.1 Les types simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.2 Les variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.3 Les constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2 Les types composés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2.1 Les tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2.2 Les enregistrements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.3 Les pointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.4 Les listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.5 Les arbres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3 Structure de programme 17
3.1 Forme générale d’un programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.1.1 Ligne de commentaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.1.2 Les expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.1.3 Les instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.1.4 Structure du texte de la fonction principale . . . . . . . . . . . . . . . . . . . 18
3.2 Les instructions simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.2.1 Instruction d’a↵ectation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.2.2 Lecture et écriture en C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.3 Les structures d’instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.3.1 Les structures de choix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.3.2 Les structures répétitives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

4 Programmes et sous-programmes C/C++ : tout est fonction ! 29


4.1 Les fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.1.1 Structure générale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.1.2 Echange d’informations entre fonctions . . . . . . . . . . . . . . . . . . . . . . 30
4.1.3 Argument, paramètre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.1.4 Portée d’une variable, d’un paramètre . . . . . . . . . . . . . . . . . . . . . . 30
4.1.5 Passage par valeur, passage par référence . . . . . . . . . . . . . . . . . . . . 31
4.2 Traduction quand une seule valeur de type simple ou un enregistrement est renvoyée 33
4.2.1 Exemples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.2.2 Utilisation dans la fonction appelante . . . . . . . . . . . . . . . . . . . . . . 34
4.3 Traduction quand un tableau et/ou plusieurs valeurs sont renvoyés . . . . . . . . . . 35
4.3.1 Les arguments ne doivent pas être modifiés par la fonction . . . . . . . . . . . 35

École Centrale de Nantes, — Algorithmique et programmation — 3


TABLE DES MATIÈRES TABLE DES MATIÈRES

4.3.2 Certains arguments peuvent être modifiés par la fonction . . . . . . . . . . . 36


4.3.3 Quelques critères pour choisir le type de traduction . . . . . . . . . . . . . . . 38
4.4 Programmation structurée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
4.4.1 Fonction principale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
4.4.2 Les fichiers en-tête . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
4.4.3 Instructions de compilation et fichiers ”Makefile” . . . . . . . . . . . . . . . . 42
4.4.4 Exemple de programmation structurée avec des manipulations de listes . . . 44

II GUIDE POUR LES TRAVAUX PRATIQUES 50


1 Rapport de travaux pratiques 51
1.1 Composition du dossier informatique . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
1.2 Partie algorithmique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
1.2.1 Problème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
1.2.2 Spécification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
1.2.3 Algorithme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
1.2.4 Exemple de dossier algorithmique d’une fonction principale sans appel d’une
fonction secondaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
1.2.5 Exemples d’algorithmes de fonctions . . . . . . . . . . . . . . . . . . . . . . . 53
1.3 Fichiers contenant le code de programmation . . . . . . . . . . . . . . . . . . . . . . 54
1.3.1 En-tête de présentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
1.3.2 Présentation des fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
1.3.3 Commentaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
1.3.4 Choix des identificateurs de variables . . . . . . . . . . . . . . . . . . . . . . . 55
1.4 Résultats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
1.4.1 Jeux d’essai . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
1.4.2 Analyse et commentaires sur les résultats . . . . . . . . . . . . . . . . . . . . 55

2 Exemple de rapport 56
2.1 Dossier algorithmique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.1.1 Algorithmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.1.2 Traduction en C/C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

III ANNEXE 65

Ce polycopié a été élaboré avec l’aide des enseignants des équipes pédagogiques
successives de l’enseignement d’Algorithmique et Programmation.

Cours de l’école Centrale de Nantes « Algorithmique et Programmation » (ALGPR),


c
revu et corrigé en septembre 2013.

École Centrale de Nantes, — Algorithmique et programmation — 4


Chapitre 1

Introduction

L’algorithmique et la programmation font partie d’une science appelée Informatique.


La définition de l’informatique, donnée en 1966 par l’Académie française, est la suivante :
« Science du traitement rationnel, notamment par machines automatiques, de l’information
considérée comme le support des connaissances humaines et des communications dans les
domaines techniques, économiques et sociaux. »
L’information est donc considérée comme le support des connaissances et des commu-
nications, et l’ordinateur est une des machines automatiques qui permettent d’exécuter le
traitement rationnel de l’information. Un des objectifs de l’informatique est de procéder au
traitement des informations par l’ordinateur.
L’algorithmique est l’étude des algorithmes. Un algorithme est la description d’un
traitement rationnel de l’information, à savoir la suite des opérations nécessaires pour ré-
soudre un problème donné. Cet algorithme est issu d’une phase d’analyse du problème. Il
décrit comment est réalisée une fonction qui travaille sur un ensemble de valeurs, appelées
données, fournies à l’algorithme. L’algorithme de la fonction produit un ou plusieurs ré-
sultats. Il est écrit dans un formalisme suffisamment général pour ne pas tenir compte du
langage et de la machine qui seront utilisés pour la programmation et l’exécution.
La programmation, appelée phase de codage, est la traduction d’un algorithme dans
un langage compréhensible par l’ordinateur : le langage de programmation. Le résultat de
cette phase de programmation est un code source qui est compilé en un programme
exécutable.
Ce cours comporte deux parties :
– la partie programmation, qui est la partie principale de ce cours ; contient les sché-
mas de traduction des structures algorithmiques en langage C/C++,
– la partie dossier informatique expose les di↵érents éléments que doit comporter un
dossier détaillant la résolution d’un problème par ordinateur et comporte un exemple
complet.
Des compléments au contenu de ce cours seront accessibles sur le serveur pédagogique.

École Centrale de Nantes, — Algorithmique et programmation — 5


Première partie

PROGRAMMATION
C++

École Centrale de Nantes, — Algorithmique et programmation — 6


Le C et le C++ sont deux langages distincts mais néanmoins étroitement liés dans leur
histoire.
Le C est un langage de programmation impératif développé dans les années 1970, qui a
été créé pour développer le système UNIX. C’est un langage largement utilisé et éprouvé
qui constitue une référence dans les langages de programmation. Ce langage a inspiré de
nombreux autres langages, dont le C++.
Le C++ est un langage orienté objet créé dans les années 1980 qui est initialement une
extension du C pour y ajouter des classes d’objets. L’utilisation de ces classes nécessite
néanmoins une bonne maitrise de la programmation impérative. Dans ce cours, nous utili-
serons le C++ avec une approche de programmation impérative et nous n’aborderons pas
l’utilisation des classes. Cette approche de la programmation orienté objet est laissée à ceux
qui souhaitent aller plus loin dans leurs compétences de programmation.
L’utilisation du C++, quel que soit le paradigme de programmation utilisé, permet de
bénéficier de diverses fonctionnalités qui ont été ajoutées par rapport à son prédécesseur,
entre autres : le type bool, la définition de constantes, les paramètres par défaut pour les
fonctions, les espaces de noms, le compilateur C++ et ses nombreuses librairies.
Remarques :
– Vous pouvez trouver une littérature abondante sur internet, par exemple, le site
http ://www.cplusplus.com ou le forum http ://stackoverflow.com.
– Sur les mots-clefs de C++ :
Les symboles spécifiques, ou mots-clefs, du langage C++ utilisés sont écrits dans ce
document dans ce style.
– Un identificateur est constitué d’une suite de caractères alphanumériques commen-
çant par une lettre.
– les minuscules et les majuscules sont di↵érenciées, entre autres pour les identificateurs
et les noms de fonctions.
– La portée d’une définition - respectivement d’une déclaration - est le
bloc d’instructions (délimité par des accolades), ou le fichier en cas de définition -
respectivement de déclaration - avant tout bloc d’instruction, où elle est écrite.

Il est indispensable d’écrire avec soin l’algorithme


avant de passer à sa traduction en C++

École Centrale de Nantes, — Algorithmique et programmation — 7


Chapitre 2

Données et structures de données

En C++, toute donnée (constante ou variable) doit être déclarée avant d’être uti-
lisée. Les instructions de déclaration doivent être placées au début de l’unité qui utilise ces
variables, avant toutes les autres instructions.

2.1 Les données


2.1.1 Les types simples
Les types simples sont spécifiés grâce aux mot-clés :

mot-clé type taille valeurs


char caractère 1 octet [0-9 a-z A-Z]
bool booléen 1 octet true, false
int entier 4 octets ±2.14 · 109
float réel simple précision 4 octets ±3.4 · 10±38 (7 chi↵res)
double réel double précision 8 octets ±1.7 · 10±308 (15 chi↵res)

Les informations sur la taille et la valeur sont données pour un système 32 bits, mais la
précision est au moins respectée sur un système plus récent.

Les chaı̂nes de caractères utilisent le type string. Pour cela, il faut inclure la librairie
string pour gérer les chaı̂nes de caractères avec le code suivant en début de fichier (avant
d’utiliser le type éponyme string) :
#include <string>

2.1.2 Les variables


Une variable typée est une entité permettant de mémoriser une valeur d’un type donné.
Elle est parfaitement définie par trois informations : son nom (ou identificateur), son type
et sa valeur. Dans la réalité, la valeur d’une variable ou d’une constante est stockée dans
une portion de la mémoire de l’ordinateur qui lui est dédiée.

École Centrale de Nantes, — Algorithmique et programmation — 8


Chapitre 2. Données et structures de données 2.1. Les données

⇤ Identification des variables de type simple


Un identificateur doit suivre quelques règles élémentaires :
– Être composé de caractères alphanumérique standard [0-9 a-z A-Z] et le tiret bas, par
exemple pas de caractères accentués,
– Ne pas commencer par un chi↵re
– Ne pas comporter d’autre caractères (point, espace, etc.).
Par convention, un nom de variable (ou identificateur) commence par une lettre minus-
cule.
Exemple :
vitesse, vitesseVoiture, tailleMatrice, nombreCours

Remarque : Les identifiants sont sensibles à la casse : vitesse, viTeSSe et vITESSE sont
trois identificateurs di↵érents.

⇤ Déclaration des variables de type simple


C++

int borneInf, sommeTotale; // entier, en général sur 4 octets


float normeMatrice, moyenne; // réel simple précision
char rep, carCourant;
bool a;

Remarque : Portée d’une déclaration : les instructions de déclaration doivent être placées au
début du bloc d’instruction qui utilise ces variables, ou dans un bloc d’un niveau supérieur,
et par convention avant toutes les autres instructions.

2.1.3 Les constantes


⇤ Les constantes numériques
Les constantes numériques ont les mêmes types que les variables numériques (int, float,
double).

⇤ Les constantes littérales


Une constante de type caractère est délimitée par des apostrophes.
Exemple :
’A’ /* la constante A */

Une constante littérale est une chaı̂ne de caractères constante. Elle est formée d’une
suite de caractères quelconques délimitée par des guillemets qui ne font pas partie de
la valeur du littéral. Les littéraux apparaissent principalement dans des écritures pour
constituer des messages émis par le programme.
Exemple :
"CECI EST UN LITTERAL" /* La constante CECI EST UN LITTERAL */

École Centrale de Nantes, — Algorithmique et programmation — 9


2.2. Les types composés Chapitre 2. Données et structures de données

⇤ Les déclarations de constantes


Dans le cas où une constante est nommée dans un programme, il faut substituer à ce
nom symbolique la valeur e↵ective de la constante. Ceci se fait à l’aide du mot-clef const.
A priori, s’il est nécessaire d’utiliser une constante, cela signifie qu’elle est valable pour
le programme entier, cette définition doit donc être accessible partout dans le programme,
généralement dans un fichier .h contenant les définitions des types et des constantes. C’est un
des cas d’utilisation d’une données de manière globale dans un programme. Par convention,
un identificateur de constante est écrit en majuscules.
C++
const float PI=3.1416; /* associe a PI la valeur constante 3.1416 */
const int MAXREF = 100;
const char OUI = ’o’; /* attention, OUI est un caractere ! */

Remarque : les valeurs des constantes ne sont en général pas données en algorithmique, mais
sont obligatoirement spécifiées en C++.

2.2 Les types composés


Il existe plusieurs façons de définir les types composés (en particulier pour les tableaux).
Nous proposons d’utiliser la méthode utilisant le mot-clef typedef pour les tableaux. Tout
type composé doit être déclaré avant d’être utilisé.

2.2.1 Les tableaux


⇤ Définition des types tableaux
La définition est faite avec le mot-clef typedef suivi du type des éléments du tableau,
puis du nom du type défini.
typedef (type) t_nomType[taille] ;
La combinaison d’une définition de constante (cf. section 2.1.3) et d’une définition de type
permet d’obtenir des programmes plus modulables : par exemple si la taille maximale choisie
pour un vecteur n’est plus adaptée au problème à résoudre, il n’y a qu’une seule valeur à
modifier à un seul endroit pour que cette nouvelle donnée soit connue dans tout le programme
(cf. chapitre 4, p. 29).

Exemples :
algorithme
type
t_VectEnt : vecteur d’entiers
t_MatReels : matrice de réels
t_Chaine : vecteur de caractères
variables
t_VectEnt a
Vecteur d’entiers b

École Centrale de Nantes, — Algorithmique et programmation — 10


Chapitre 2. Données et structures de données 2.2. Les types composés

C++

// Définition d’une constante NMAX


const int NMAX=10;

// Définition d’un type vecteur d’entiers de taille NMAX


typedef int t_VectEnt[NMAX];

// Déclaration d’une variable a de type Vecteur d’entiers


t_VectEnt a;

// Définition et déclaration directe d’un tableau d’entiers de taille NMAX


int b[NMAX];

// Définition d’un type matrice carrée de réels de taille NMAXxNMAX */


typedef float t_MatReels[NMAX][NMAX] ;

// Définition d’une constante MAXCAR


const int MAXCAR=50;

// Définition d’un tableau de caractères de taille MAXCAR


typedef char t_Chaine[MAXCAR];

⇤ Déclaration des variables de type tableaux


Il s’agit simplement d’indiquer qu’une variable (dont on donne le nom) est d’un certain
type (indiqué devant le nom de la variable). Ce type doit avoir été précédemment défini et
être accessible.
Exemples :
/* Déclaration d’une matrice de réels avec les indices allant de 0 à 9 :
matReels[0][0] à matReels[9][9], la définition du type t_MatReels a déjà
été faite. */
t_MatReels matReels ;

Accès aux éléments du tableau :

Pour un vecteur, un élément est repéré par son indice placé entre crochets, après le nom
du vecteur.

Exemples :
(les types des variables étant supposés compatibles) :
v[i]=a ; a=v[i+2] ; v[i] = v[i+2] ;
Pour une matrice, chaque élément doit être repéré par deux indices, chacun étant placé
entre crochets à la suite du nom de la matrice.
Exemple :
M[i][j] = 0.2 ;

École Centrale de Nantes, — Algorithmique et programmation — 11


2.2. Les types composés Chapitre 2. Données et structures de données

Pour un tableau de dimension supérieure à 2, chaque élément doit être repéré par autant
d’indices placés entre crochets à la suite du nom du tableau que le tableau a de dimensions.
Exemple :
T[2][J][J+1]=5 ;
Attention : En interne, le langage C++ gère un tableau comme un pointeur constant sur
le premier élément. Cela explique un certain nombre de restrictions sur leur utilisation que
nous détaillerons dans la suite.

⇤ Chaı̂nes de caractères
Une chaı̂ne de caractères est une suite de caractères représentant, en général, un texte.
Par exemple, "Bonjour" est une constante de type chaı̂ne de caractères (on parle aussi de
constante littérale).
Le langage C++ ne définit pas de type « chaı̂ne de caractères » à proprement parler : une
chaı̂ne de caractères est définie en C++ comme un tableau de caractères à une dimension.
La taille du tableau n’est pas importante mais le dernier caractère doit être le caractère \0.
Pour définir un type chaı̂ne de caractères t_Chaine on pourra ainsi écrire :
C++
typedef char t_Chaine[256]; // Un tableau de caractères de taille 256
De nombreuses fonctions de manipulation des chaı̂nes de caractères sont disponibles en
incluant la bibliothèque string. On y trouve notamment la définition d’un type chaı̂nes de
caractères (string), des fonctions pour copier des chaı̂nes de caractères et les concaténer.

2.2.2 Les enregistrements


⇤ Définition des types enregistrement
La définition des types enregistrement se fait à l’aide de struct, suivi par le nom du
type défini, puis de la définition successive de tous les champs, de la façon suivante :
algorithme
Exemple :
type type
NomDuType : Enregistrement t_Article : Enregistrement

(type1) champ1 entier reference


(type2) champ2 chaine libelle
Fin_enregistrement Fin_enregistrement

C++
Exemple :
struct NomDuType struct t_Article
{ {
(type1) champ1; int reference;
(type2) champ2; string nom;
}; };

École Centrale de Nantes, — Algorithmique et programmation — 12


Chapitre 2. Données et structures de données 2.2. Les types composés

On peut, bien sûr, créer des types composés de types composés tels que des tableaux
d’enregistrements par exemple.

⇤ Déclaration de variables de type enregistrement


En supposant défini le type t_Article, le type vecteur d’articles dont chaque élément
est de type t_Article est défini ainsi :
const int MAXREF=100; // association a MAXREF de la valeur entiere 100
typedef t_Article t_VectArticles[MAXREF];

La déclaration de variables de types t_Article ou t_VectArticle, se fera par :

Exemple :
algorithme
variables
t_Article artCour
t_VectArticle mesArticles

C++
t_Article artCour; // artCour est de type t_Article
t_VectArticle mesArticles; // vecteur d’éléments de type t_Article

2.2.3 Les pointeurs


Une variable typée est une entité permettant de mémoriser une valeur d’un type donné.
Elle est parfaitement définie par trois informations : son nom, son type et sa valeur.
Dans la réalité, la valeur d’une variable 1 est stockée dans une portion de la mémoire de
l’ordinateur qui lui est dédiée.
Pour un programme donné, la mémoire de l’ordinateur peut-être vue comme un tableau
où chaque case peut contenir un octet (8 bits). L’indice d’une case dans le tableau est appelé
son adresse mémoire.
Par exemple, sur les ordinateurs actuels, les entiers sont codés le plus souvent sur 32
bits, soit 4 octets. Une variable entière int occupe donc 4 cases contiguës dans la mémoire.
Son adresse mémoire est l’indice de la première de ces 4 cases et c’est le type de la variable
qui indique combien de cases il faut considérer à partir de l’adresse mémoire pour retrouver
le contenu de la variable.
En C++, il existe un type représentant les adresses mémoire : le type pointeur. Ainsi,
une variable de type « pointeur sur un entier » est destinée à contenir l’adresse mémoire
d’une variable de type entier.
Pour chaque type de donnée T (y compris les types définis par l’utilisateur, cf. infra),
on peut ainsi définir un type « pointeur sur T ». En C++, ce type est noté T*. Par exemple
pour déclarer une variable p de type « pointeur sur un entier », on utilisera la syntaxe
int* p;

1. Ou d’une constante, mais on se concentrera sur les variables dans cette partie.

École Centrale de Nantes, — Algorithmique et programmation — 13


2.2. Les types composés Chapitre 2. Données et structures de données

1000 1001 1002 1003


... 42 ... Mémoire
(Valeur de a)

a
(de type int)

1001
(Valeur de p)

p
(Pointeur sur a de type int*)

Figure 2.1 – Illustration d’un pointeur p de type int * sur un entier a. Le pointeur a pour
valeur l’adresse de a.

Afin de pouvoir donner des valeurs à nos pointeurs, le langage C++ propose également
une construction pour récupérer l’adresse d’une variable donnée : si a est une variable alors
&a est l’adresse mémoire de a.
Enfin, on peut accéder au contenu d’une variable par l’intermédiaire d’un pointeur sur
cette variable. On parle de déréférencement du pointeur : si p est un pointeur sur une
variable a alors *p est le contenu de la variable a.
C++
int a; // une variable entière
int *p; // un pointeur sur une variable entière
p = &a; // p pointe sur a
*p = 2; // a vaut maintenant 2
Un pointeur est une variable qui contient l’adresse d’une autre variable. Nous pouvons
allouer manuellement une case dans la mémoire pour stocker la valeur d’une variable. Pour
cela il faut utiliser l’opérateur new. new demande une case à l’ordinateur et renvoie un
pointeur pointant vers cette case.
Par exemple :
C++
int *p;
p = new int;
Ici il y aura deux cases mémoire utilisées. La deuxième ligne demande une case mémoire
pouvant stocker un entier et l’adresse de cette case est stockée dans le pointeur qui a été
déclaré à la première ligne.

Pour libérer de la mémoire préalablement a↵ectée à un pointeur, on utilise delete (voir


4.4.4 pour un exemple d’utilisation).
delete p;
L’utilisation des pointeurs permet notamment l’accès à certaines fonctionnalités de très
bas niveau, des optimisations de performances, un début de généricité (traitements iden-
tiques pour des types di↵érents) et l’allocation dynamique de mémoire (au moment de
l’exécution). Mais toutes ces notions ne seront pas abordées dans ce document.

École Centrale de Nantes, — Algorithmique et programmation — 14


Chapitre 2. Données et structures de données 2.2. Les types composés

Nous verrons cependant comment les pointeurs peuvent être utilisés pour contourner les
limitations du langage C++ en termes de valeurs de retour des fonctions, ou pour définir
des types récursifs.

Accès aux champs d’un enregistrement avec un pointeur

Dans le cas où on dispose de pointeurs sur des enregistrements, l’accès peut se faire
par l’utilisation de l’opérateur de déréférencement * puis le ., mais le langage propose un
opérateur plus simple noté ->.
Exemple :

t_Article *ptrArticle;
...
// accès avec le déréférencement du pointeur
(*ptrArticle).reference = 42;
...
// accès avec utilisation directe du pointeur
ptrArticle->reference = 23;
ptrArticle->libelle = "stylo";

2.2.4 Les listes

Nous allons nous intéresser au cas particulier des listes chainées, par exemple d’entiers.
Chaque élément de la liste est composé de :
– une valeur (une étiquette) ; dans l’exemple, c’est un entier,
– un pointeur vers l’élément suivant. Cas particulier du dernier élément de la liste où le
lien ne pointe vers rien. En C++, elle pointe vers un élément NULL.
algorithme

type t_ListeEntier : Enregistrement


entier valeur
t_ListeEntier : suivant //pointe sur l’entier suivant
Fin_enregistrement

C++

struct t_ListeEntier
{
// type de la donnée : un entier
int valeur;
// pointeur sur l’élément suivant
t_ListeEntier* suivant;
};

École Centrale de Nantes, — Algorithmique et programmation — 15


2.2. Les types composés Chapitre 2. Données et structures de données

2.2.5 Les arbres


Nous allons nous intéresser au cas particulier des arbres binaires où les nœuds de l’arbre
ont pour valeur des caractères. Chaque nœud de l’arbre est composé de :
– une valeur (une étiquette) ; dans l’exemple, c’est un caractère,
– un pointeur vers son fils gauche, si il n’y a pas de fils gauche la flèche pointe vers un
élément NULL.
– un pointeur vers son fils droit, si il n’y a pas de fils droit la flèche pointe vers un
élément NULL.
algorithme

type
t_arbreCar : Enregistrement
caractères valeur,
t_arbreCar filsGauche, // pointe sur le fils gauche
t_arbreCar filsDroit, // pointe sur le fils droit
Fin_enregistrement

C++
struct t_arbreChar
{
// type de la donnée : un caractère
char valeur;
// pointeur sur le fils gauche
t_arbreChar* filsGauche;
// pointeur sur le fils droit
t_arbreChar* filsDroit;
};

École Centrale de Nantes, — Algorithmique et programmation — 16


Chapitre 3

Structure de programme

3.1 Forme générale d’un programme


Un programme est composé d’instructions et des commentaires C++.

3.1.1 Ligne de commentaire


C++

/* CECI EST UN COMMENTAIRE


il peut tenir
sur plusieurs lignes */

// ceci est un commentaire C++ ne dépassant pas la fin de ligne

3.1.2 Les expressions


Elles sont construites à partir des variables et des constantes de mêmes types, et grâce
aux opérateurs associés à ces types.

⇤ Les opérateurs de comparaison


algorithme
<  =
6 = >
C++
< <= != == >= >
Exemple :
En C++ avec A = 2, B = 3 et C = 5 :
A == (C - B) aura la valeur true
(B + C - A) <= 0 aura la valeur false .

Remarque importante : Attention, dans une condition, l’écriture (a=b) est interprétée
comme l’a↵ectation à a de la valeur de b, et le résultat de l’évaluation de cette condition est
vrai (6= 0) si cette valeur n’est pas nulle. Ne pas la confondre avec la comparaison (a==b).

École Centrale de Nantes, — Algorithmique et programmation — 17


3.1. Forme générale d’un programme Chapitre 3. Structure de programme

⇤ Les opérateurs logiques


algorithme
et ou non
C++
&& || !

3.1.3 Les instructions


algorithme
éventuellement, mais exceptionnellement plusieurs instructions par ligne, séparées par
un ;
C++
une instruction est toujours terminée par un ;
S’il y a plusieurs instructions sur une même ligne, elles sont donc séparées par un ; (à
réserver aux instructions courtes, ne faisant pas partie d’une structure).

3.1.4 Structure du texte de la fonction principale


Toutes les unités constituant un programme sont des fonctions. L’exécution d’un pro-
gramme débute par l’appel d’une fonction particulière du programme appelée fonction prin-
cipale. Son nom réservé est main, elle est de type ”int”.

Structure de la fonction principale :


/* ============================================================================
Identification : precisant les auteurs, la date et le nom du programme
----------------------------------------------------------------------------
Documentation : donner les indications permettant de comprendre le code
============================================================================ */

/* Directives d’inclusion de fichiers */


// Exemple : inclusion du fichier iostream necessaire pour les lectures/ecritures
#include <iostream> // remarque : pas de point virgule pour les inclusions

// Indication que l’on utilise l’espace de nom ’std’


// pour simplifier l’utilisation des fonctions standards
using namespace std;

int main () {
// Déclarations des variables et constantes locales
........................................ ;
........................................ ;
// corps de la fonction principale : instructions exécutables et commentaires
........................................ ;
........................................ ;
// On renvoie 0 pour indiquer que le programme s’est bien terminé
return 0 ;
}

École Centrale de Nantes, — Algorithmique et programmation — 18


Chapitre 3. Structure de programme 3.2. Les instructions simples

3.2 Les instructions simples


3.2.1 Instruction d’a↵ectation
⇤ Forme générale :
Elle traduit l’action de modification de la valeur d’un objet : cible source
et a la forme suivante :
variable = source;
La variable, cible de l’a↵ectation, est de type scalaire (numérique, logique, caractère,
. . . ) ou est un enregistrement. La source exprime la valeur, de même type, qui doit être
donnée à la variable. La source peut être une constante, une autre variable ou le résultat
d’une opération pouvant inclure des constantes et des variables.

Remarque importante : si les variables sont de type tableau, l’a↵ectation doit se faire
élément par élément.

⇤ A↵ectation pour le type numérique (entier, réel) :


La source peut apparaı̂tre sous la forme d’une constante unique, d’une variable
unique, d’une expression numérique comportant des opérateurs arithmétiques associés à des
constantes et/ou variables, des paires de parenthèses, des références de fonctions à résultat
numérique.
Exemple :
algorithme
SX Sinus(A + 3.*Y) - Y/(Z - 1.41)

C++
SX = sin(A + 3.*Y) - Y/(Z - 1.41);
Les 4 opérateurs arithmétiques (+ - * /) sont identiques en Algorithmique et en C++.
De plus, le modulo existe en C++, il est noté %.

Remarque importante : attention aux types des opérandes et donc au résultat final, si n
et m sont de type entier, / désigne la division entière et n/m est un entier.
int a, b;
float c;
c = 2/3; // c = 0, division entière
c = 2/3.; // 3 est un float pour cette opération : c = 0.666667
c = 2./3; // 2 est un float pour cette opération : c = 0.666667
a = 2;
b = 3;
c = a/b; // c = 0, division entière
c = (float)a/b; // a est un float pour cette opération : c = 0.666667
// (float) est un transtypage explicite

École Centrale de Nantes, — Algorithmique et programmation — 19


3.2. Les instructions simples Chapitre 3. Structure de programme

⇤ A↵ectation pour les types composés :


L’a↵ectation d’une variable de type composé se fait :
– pour les tableaux, composante par composante,
– pour les enregistrements, en bloc pour toute la structure ou champ par champ.

Exemple :
algorithme
mesArticles[1] artCour ;
v1 v2 ; /* vecteur d’entiers */

C++
mesArticles[1] = artCour ; /* affectation globale */

/* attention : affectation composante par composante, utilisation


d’une structure iterative - les 2 vecteurs de type t_VectEnt sont
supposes de taille n, voir plus loin les boucles */
for (i=0 ; i<n ; i=i+1)
{
v1[i] = v2[i];
}

3.2.2 Lecture et écriture en C++


Les lectures/écritures en C++ font appel à des fonctions standards prédéfinies nécessitant
l’inclusion de la librairie iostream :
#include <iostream>
L’appel aux fonctions standard se fait alors en les préfixant par std::
std::cin
std::cout
L’utilisation de l’espace de noms standard permet d’éviter le préfixe std::
Ceci permet de simplifier l’utilisation des fonctions de la bibliothèque standard du C++.
Nous considérons dans la suite que nous utilisons l’espace de noms standard.
using namespace std;
La lecture ou l’écriture d’une variable de type composé se fait champ par champ pour
un enregistrement, composante par composante pour un tableau.

École Centrale de Nantes, — Algorithmique et programmation — 20


Chapitre 3. Structure de programme 3.2. Les instructions simples

⇤ Lecture au clavier du terminal :


Les valeurs à lire sont extraites d’un flot d’entrée, appelé cin.

Exemple pour des variables de types simples :


algorithme
uneVariable lire ()
{var1,var2,var3} lire ()

C++
cin >> uneVariable; // lecture d’une valeur au clavier
cin >> var1 >> var2 >> var3; // lecture de 3 valeurs
Exemple pour des variables de types composés :

algorithme
{mesArticles(1), v2} lire ()

C++ :
// lecture champ par champ de mesArticles[1]
cin >> mesArticles[1].reference
>> mesArticles[1].libelle
>> mesArticles[1].prix;

// lecture composante par composante


for (i=0 ; i<n ; i=i+1)
{
cin >> v2[i];
}

⇤ Affichage à l’écran du terminal :


L’écriture se fait dans un flot de sortie, appelé cout.

Exemple pour des variables de types simples :

algorithme
écrire (var1,var2,var3)
écrire ("la racine de x" + r)

C++
// affichage des valeurs de 3 variables (pas forcément de m^eme type)
// on note que les valeurs seront pas séparées par un espace
cout << Var1 << Var2 << Var3 << endl;
// composition de différentes sorties
cout << "la racine est x=" << r << endl;
// pour aller à la ligne, utilisation de endl (end line)

École Centrale de Nantes, — Algorithmique et programmation — 21


3.2. Les instructions simples Chapitre 3. Structure de programme

Exemple pour des variables de types composés :

algorithme
écrire ((mesArticles(1), v2))

C++ :
// écriture champ par champ d’un "article"
cout << mesArticles[1].reference << " "
<< mesArticles[1].libelle << " "
<< mesArticles[1].prix << endl;

for (i=0 ; i<n ; i=i+1)


{
cout << v2[i] << " ";
}
cout << endl;

⇤ Lecture ou écriture sur fichier :


Les lectures et écritures dans un fichier sont séquentielles. C’est-à-dire que l’on peut
imaginer que l’opération courante est faite dans le fichier au niveau d’un curseur qui est
déplacé immédiatement après l’opération sur l’élément suivant. Elles nécessitent l’inclusion
de la librairie fstream et l’utilisation de l’espace de noms standard :
#include <fstream>
using namespace std;
Remarque : Un espace de noms ne doit être déclaré qu’une fois dans le programme. Si l’espace
de nom standard std a déjà été déclaré après de l’inclusion de la bibliothèque iostream il
est inutile de recommencer.

Utilisation. L’utilisation de fichiers comporte les phases suivantes :


— la déclaration du curseur sur le fichier : fstream monFichier ;
— l’ouverture, qui peut prendre l’une des trois formes :
- monFichier.open("donnees.txt",ios::in); pour pouvoir lire dans le fichier
- monFichier.open("donnees.txt",ios::out); pour pouvoir écrire dans le fichier en
écrasant ce qu’il y avait éventuellement avant l’ouverture
- monFichier.open("donnees.txt",ios::app|ios::out)); pour pouvoir écrire dans le
fichier après ce qu’il y a éventuellement au moment de l’ouverture 1
— la lecture ou l’écriture, qui se font avec les opérateurs notés << et >> comme pour
les opérations similaires sur le terminal (cf. sections 3.2.2 et 3.2.2, p. 21)
— la fermeture qui se fait par monFichier.close();

1. ‘‘app” est l’abréviation de ‘‘append” qui signifie en l’occurrence ajouter.

École Centrale de Nantes, — Algorithmique et programmation — 22


Chapitre 3. Structure de programme 3.2. Les instructions simples

Noms de fichier physique et de fichier logique.


– monFichier est un nom de variable qui permet de faire référence, dans le programme,
à un « flot » d’entrée ou de sortie qui représente le fichier : c’est le nom logique,
– donnees.txt est le nom d’un fichier reconnu par le système d’exploitation : c’est le
nom physique.

Remarques :
– En écriture si le fichier donnees.txt n’existe pas, il est créé.
– En lecture si le fichier donnees.txt n’existe pas ou s’il n’est pas dans le répertoire
d’exécution du programme, il y aura une erreur à l’exécution.
– Comme pour les écritures sur le terminal, il est possible de mettre des « passages à la
ligne » dans les fichiers :
monFichier<<endl ; // passage à la ligne dans monFichier, donc dans don-
nées.txt
– Le booléen monFichier.eof(), qui est mis à vrai quand une lecture est tentée après
la fin de fichier, permet de tester si le curseur est arrivé en fin de fichier.

École Centrale de Nantes, — Algorithmique et programmation — 23


3.2. Les instructions simples Chapitre 3. Structure de programme

Exemple de programme comportant des lectures/écritures dans un fichier :

/* ==============================================================================
O. Roux Departement I & M
Programme LireEcrire 02-07-02
---------------------------------------------------------------------------------
BUT DU PROGRAMME : ILLUSTRER L’UTILISATION DE FICHIERS EN LECTURE/ECRITURE EN C++
Une phrase est placee dans le fichier resultat.dat dont on lit ensuite le contenu
============================================================================== */

// inclusion des fonctions de lectures/écritures sur flot de données


#include <iostream>
// inclusion des fonctions de lectures/écritures sur les fichiers
#include <fstream>
// inclusion du type ’string’
#include <string>

// utilisation de l’espace de nom standard


using namespace std;

int main () {
// DECLARATION DES VARIABLES
string uneChaine;
fstream fichier,out;

// ECRITURE DANS LE FICHIER => OUVERTURE EN ECRITURE (ajout à la fin)


fichier.open("resultat.txt",ios::app|ios::out) ;
fichier << "Il fait beau aujourd’hui" ; // tous les mots sur une seule ligne
fichier.close() ;

// LECTURE DANS LE FICHIER => OUVERTURE EN LECTURE


fichier.open("resultat.txt",ios::in) ;
while (!fichier.eof()) {
fichier >> uneChaine; // lecture de séparateur à séparateur, ici l’espace
cout << uneChaine << endl; // un mot par ligne à l’écran
}
fichier.close();

// FIN DE LA FONCTION PRINCIPALE


return 0;
}
Résultat (affichage à l’écran du contenu, mot par mot, du fichier resultat.txt si ce fichier
contenait ”Météo :” avant l’exécution) :
Météo:
Il
fait
beau
aujourd’hui

École Centrale de Nantes, — Algorithmique et programmation — 24


Chapitre 3. Structure de programme 3.3. Les structures d’instructions

3.3 Les structures d’instructions


3.3.1 Les structures de choix
⇤ La structure conditionnelle : if ...else
Elle apparaı̂t dans une structure de choix simple, alternatif ou éventuellement de choix
multiples. Elle sert à exprimer la réalisation conditionnelle d’instructions.
– Réalisation conditionnelle d’une séquence d’instructions (sans alternative) :
algorithme
Exemple :
si ( P ) alors si ( AB ) alors
| instructions | xMax B ; xMin A
fin si fin si
C++
Exemple :

if (P)
if (A <= B)
{
{
// liste d’instructions
xMax = B;
}
xMin = A;
}
Si P est vraie, la suite d’instructions instructions est réalisée, si P est fausse, on
sort directement de la structure pour poursuivre avec l’instruction qui suit l’accolade
fermante } .

École Centrale de Nantes, — Algorithmique et programmation — 25


3.3. Les structures d’instructions Chapitre 3. Structure de programme

– Réalisation alternative d’une séquence d’instructions :


algorithme
Exemple :
si ( P ) alors si ( A>B ) alors
| instructions 1 | xSup A ; xInf B
sinon sinon
| instructions 2 | xSup B ; xInf A
fin si fin si
C++
Exemple :

if (A > B)
if (P) {
{ xSup = A;
// liste d’instructions xInf = B;
} }
else else
{ {
// autre liste d’instructions xSup = B;
} xInf = A;
}
Si P est vraie , instructions 1 est réalisée, puis on sort de la structure pour pour-
suivre avec l’instruction suivant la dernière } de cette instruction conditionnelle.
Si P est fausse, c’est directement instructions 2 qui est réalisée, puis on sort de la
structure pour poursuivre avec l’instruction suivant la dernière } de cette instruction
conditionnelle.

⇤ La structure sélective : switch


Elle traduit une instruction de choix multiples dans le cas particulier où ce choix se fait
selon la valeur d’une variable de type entier ou caractère.
algorithme
choix selon
| var=val1 : Exemple :
| | instructions 1 choix selon
| var=val2 : | ind=1 :
| | instructions 2 | | écrire ("2 racines réelles")
| ... | ind=-1 :
| var=valN : | | écrire ("2 racines complexes")
| | instructions N | autre :
| autre : | | écrire ("1 racine double")
| | instructions N+1 finchoix
finchoix

où var est une variable de type entier ou caractère et val1, val2, . . . , valN des
valeurs possibles de cette variable. Dans l’exemple, ind est de type entier.

École Centrale de Nantes, — Algorithmique et programmation — 26


Chapitre 3. Structure de programme 3.3. Les structures d’instructions

C++
switch (var) Exemple :
{
case val1:
// instructions switch(ind)
break; {
case val2: case 1: cout << "2 racines reelles" << endl;
// instructions break;
break: case 2: cout << "2 racines complexes" << endl;
... break;
default: default: cout << "1 racine double" << endl;
// instructions }
}
Remarques :
– L’instruction break permet d’aller à l’instruction suivant l’accolade fermante termi-
nant le bloc switch.
– Si dans l’algorithme, les conditions de choix ne sont pas du type var=vali avec var
de type entier ou caractère, il faut traduire la structure algorithmique par des if
...else imbriqués.

3.3.2 Les structures répétitives


⇤ L’instruction for
Elle traduit la structure itérative ”pour ... à ... faire /fin pour ”,.
algorithme
Exemple :
pour i iDeb à iFin (pas n lire () ; som 0
iPas) faire pour i 1 à 2*n (pas2) faire
| instructions | som som+i
fin pour fin pour

C++
Exemple :

cin >> n;
for (i=iDeb;i<=iFin;i=i+iPas) som=0;
{ for (i=1;i<=2*n;i=i+2)
// instructions {
} som=som+i;
}
Remarque : l’instruction for est plus générale que la structure algorithmique ”pour”.
Sa syntaxe est : for (initialisation ; condition ; incrémentation) où :
– initialisation permet d’initialiser la boucle,
– condition en devenant fausse permet de terminer la boucle,

École Centrale de Nantes, — Algorithmique et programmation — 27


3.3. Les structures d’instructions Chapitre 3. Structure de programme

– incrémentation agit sur la valeur de la condition.

⇤ L’instruction while
Elle traduit la structure itérative ”tant que ... faire / fin tant que ”. C’est la
structure itérative la plus générale.
algorithme
Exemple :
som 0
instructions 1 //initialisations lire ((x))
tant que P faire tant que x>0 faire
| instructions 2 | som som+x
fin tant que | écrire ((som))
| lire ((x))
fin tant que

C++
Exemple :

som=0;
// instructions 1 cin >> x;
while (P) while (x>0)
{ {
// instructions 2 som=som+x;
} cout << "somme " << som << endl;
cin >> x;
}

École Centrale de Nantes, — Algorithmique et programmation — 28


Chapitre 4

Programmes et sous-programmes
C/C++ : tout est fonction !

Ce qu’on appelle communément sous-programme est un ensemble d’instructions pouvant


être ”appelé” dans di↵érents contextes mais qui ne peut pas être exécuté seul. Tous les sous-
programmes en C/C++ ont la même structure de type fonction.
Un programme est formé de fonctions qui peuvent être écrites et compilées indépen-
damment les unes des autres. Celle qui constitue la fonction principale a pour nom réservé
main : son exécution initialise la réalisation du programme complet par les éventuels appels
de fonctions.
La majorité des exemples utilisés dans ce chapitre sont des traductions des fonctions
présentées dans le chapitre 7 de la partie II (Analyse descendante - Fonctions) du cours
d’algorithmique.

4.1 Les fonctions

4.1.1 Structure générale

Toute fonction, qu’il s’agisse de la fonction principale ou non, possède la même structure.
Un fichier source contenant des fonctions C/C++ se présente de la manière suivante :
– des commentaires de présentation,
– des directives éventuelles d’inclusion de fichiers, placées après ces commentaires,
– La définition d’une ou plusieurs fonctions contenant :
– le prototype de la fonction :
unType nomDeFonction(liste-paramètres)
– le corps de la fonction entre { et } ,
– s’il y a lieu, une instruction return suivie du résultat renvoyé par la fonction.

Notez que la fonction principale, de nom réservé main, est nécessairement de type int
(cf. section 3.1.4, p.18).

École Centrale de Nantes, — Algorithmique et programmation — 29


4.1. Les fonctions Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction !

4.1.2 Echange d’informations entre fonctions


Des informations sont en général transmises entre la fonction appelante et la fonction
appelée, par l’intermédiaire de la liste de paramètres (”liste-paramètres”). La fonction
appelante peut être la fonction principale ou une autre fonction.
La ”liste-paramètres” peut être vide (pas d’échange d’information par ce moyen),
mais dans ce cas il faut néanmoins conserver le parenthésage :
unType nomDeFonction( )

L’instruction return permet de renvoyer à la fonction appelante au plus une seule valeur
de type (noté ici unType) scalaire ou enregistrement. Si la fonction appelée ne doit rien
renvoyer à la fonction appelante par ce biais, elle est déclarée de type void et ne comporte
pas d’instruction return.
Attention : pour des raisons de clarté et de facilité de vérification du code écrit, il est
demandé de n’écrire qu’au plus une instruction return par fonction et de l’écrire en dernière
instruction. En e↵et, cette instruction arrête le déroulement de la fonction : toute instruction
écrite après ne serait pas exécutée.

4.1.3 Argument, paramètre


Un argument est une information venant de la fonction appelante. Cette information
est transmise à la fonction appelée en le faisant apparaı̂tre dans la liste des arguments de
l’appel. Il peut être :
– une constante,
– une variable, indicée ou non, qui peut être de type simple ou composé,
– une expression, elle est préalablement évaluée et sa valeur est transmise à l’unité
appelée,
– ou le nom d’une fonction.

Un paramètre identifie un objet d’une fonction et est destiné à être associé à un argument
lors de l’activation du programme. Il doit donc apparaı̂tre dans la liste des paramètres du
prototype de la fonction et être normalement déclaré dans cette liste, par son type et son
nom. Ce paramètre ne peut être qu’un nom de :
– variable non indicée, de type simple ou composé,
– fonction, ce cas n’est pas étudié dans ce polycopié.

Attention : au moment de l’appel, arguments et paramètres doivent correspondre en nombre


et type, l’association se faisant un à un, dans l’ordre où ils sont écrits, de gauche à droite.

4.1.4 Portée d’une variable, d’un paramètre


La portée d’une variable est soit :
– un fichier, si elle est déclarée en début de fichier (avant toute accolade), c’est donc une
variable globale. Cette pratique est déconseillée.
– une fonction, si elle est déclarée après l’accolade commençant le corps de la fonction,
on parle alors de variable locale à la fonction,

École Centrale de Nantes, — Algorithmique et programmation — 30


Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction ! 4.1. Les fonctions

– un bloc d’instructions, si elle est déclarée à l’intérieur d’un tel bloc, délimité par des
accolades.

Toute variable définie à l’intérieur d’une fonction sera connue localement dans cette
fonction à partir de sa déclaration et jusqu’à l’accolade fermante correspondant à l’accolade
ouvrante après laquelle elle a été déclarée.
La portée d’un paramètre est la fonction dont il est paramètre.

4.1.5 Passage par valeur, passage par référence


Un argument d’appel est dit passé par valeur, s’il y a création d’une variable (copie de
l’argument) locale à la fonction appelée
– de durée de vie limitée à celle de cette fonction,
– dont la valeur initiale est celle de l’argument d’appel.
Dans ce cas, une modification du paramètre lui correspondant dans la fonction appelée
n’induit pas une modification de la valeur de l’argument. Le paramètre correspondant à un
argument passé par valeur est donc assimilable à une variable locale à la fonction appelée,
initialisée dans la fonction appelante.

En C++, un argument peut être passé par référence. Il n’y a qu’un seul objet en mémoire,
l’argument de la fonction appelante, connu sous deux noms éventuellement di↵érents :
– son nom en tant qu’argument, utilisé dans la fonction appelante,
– son nom en tant que paramètre, utilisé dans la fonction appelée.
L’association entre l’argument et le paramètre permet alors, en modifiant la valeur du
paramètre dans la fonction appelée, de modifier la valeur de la variable définie dans la
fonction appelante. En C++ le passage par référence d’un argument est noté par un &
placé entre le type et le nom du paramètre correspondant.

En C++, l’utilisation des références permet d’accéder au contenu d’une case mémoire
donnée en utilisant plusieurs ”alias” sur cette case mémoire, plusieurs références. Voyons un
exemple dans un programme principal qui afficherait le contenu d’une variable soit directe-
ment en passant par la variable soit en utilisant une référence sur cette variable.

École Centrale de Nantes, — Algorithmique et programmation — 31


4.1. Les fonctions Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction !

C++

#include <iostream>
using namespace std;

int main()
{
int age = 20; //Une variable pour contenir un entier

int & referenceSurAge = age; //une référence sur la variable ’age’

//On peut utiliser à partir d’ici


//’age’ ou ’referenceSurAge’ indistinctement
//Puisque ce sont deux étiquettes de la m^
eme case en mémoire

// Soit on utilise pour l’affichage directement la variable


cout << "Vous avez " << age << " ans. (via variable)" << endl;

// Soit on effectue l’affichage en utilisant la référence


cout << "Vous avez " << referenceSurAge << " ans. (via reference)" << endl;

return 0;
}
L’exécution de ce code donne :
Vous avez 20 ans. (via variable)
Vous avez 20 ans. (via reference)
Cet exemple est un peu artificiel. Le passage par référence va surtout nous permettre de
modifier les valeurs des variables passées en paramètres d’une fonction et ainsi permettre à
une fonction écrite en C++ de ”renvoyer” plusieurs résultats (voir 4.3.2 pour un exemple).
Attention : un argument de type tableau est automatiquement passé par adresse en C++.
C’est l’adresse mémoire de son premier élément (celui d’indice(s) 0) qui est passé à la fonction
appelée, concrètement, cela signifie qu’un tableau sera modifiable par toute fonction auquel
il sera passé en argument.

École Centrale de Nantes, — Algorithmique et programmation — 32


Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction
4.2. Traduction
! quand une seule valeur de type simple ou un enregistrement est renvoyée

4.2 Traduction quand une seule valeur de type simple ou un


enregistrement est renvoyée
Dans le cas où dans la déclaration : unType nomDeFonction(liste-paramètres)
le type unType est soit un type scalaire simple (int, float, char, ...) soit un enregis-
trement préalablement déclaré :
– le résultat de l’exécution de la fonction est renvoyé à la fonction appelante par l’ins-
truction return.
– les couples paramètres/arguments doivent servir uniquement à l’entrée (passage par
valeur).

4.2.1 Exemples
algorithme
fonction nomDeLaFonction Exemple :
spécification : fonction somme
fonction : {. . . } nomDeLaFonction(. . .) spécification :
paramètres : . . . fonction : s somme(a,b)
résultats : ... paramètres : entier a, b
début
résultats : entier s
// corps de la fonction début
... / corps de la fonction /
/*valeur à retourner de type simple, ou s a+b
enregistrement, si res est cette valeur :*/ renvoyer s
renvoyer res fin
fin

C++
Exemple :
/type/ nomDeLaFonction(ListeParametres)
{
/* fonction renvoyant la somme entiere
/* déclarations internes à la fonction */
de ses deux parametres entiers */
... ;//dont res du type renvoyé
/* corps de la fonction */ int somme (int a, int b)
... ; {
/* si res est la valeur à retourner */ int s;
return res ; s = a + b;
} return s;
}

Le prototype de la fonction somme sera :

int somme (int a, int b)


Nous retrouvons dans le prototype d’une fonction tous les éléments de sa spécification algo-
rithmique.
Une fonction sommeVectEnt(v,n) qui aurait la spécification suivante :

École Centrale de Nantes, — Algorithmique et programmation — 33


Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction !
4.2. Traduction quand une seule valeur de type simple ou un enregistrement est renvoyée

type
t_VectEnt : vecteur d’entiers

fonction sommeVectEnt
problème : Faire la somme des n premières valeurs d’un vecteur d’entier passé en
paramètre.
spécification :
fonction : s sommeVectEnt(D,n)
paramètres : t VectEnt D, entier n
résultats : entier s
aurait pour prototype (si le type t VectEnt est déclaré par ailleurs) :
int sommeVectEnt(t_VectEnt D, int n)

4.2.2 Utilisation dans la fonction appelante


Lorsque, dans une fonction, on fait appel à une autre fonction, la liste des arguments
sur laquelle est appelée cette fonction doit correspondre dans l’ordre, en type et en nombre
aux paramètres de la fonction appelée.

Exemple :
en utilisant les fonctions somme et sommeVectEnt déclarées ci-dessus :
algorithme
p n*somme(2,m) //n, m et p de type entier, utilisation dans une
expression
score1 sommeVectEnt(D1, nb) //D1 de type t_VectEnt et nb entier

C++

p = n*somme(2,m);
score1 = sommeVectEnt(D1,nb);

École Centrale de Nantes, — Algorithmique et programmation — 34


Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction ! 4.3. Traduction quand un tableau et/ou plusieurs valeurs sont renvoyés

4.3 Traduction quand un tableau et/ou plusieurs valeurs sont


renvoyés
Si la fonction renvoie un tableau et / ou plusieurs valeurs, sa traduction peut se faire :
– soit en utilisant un nouveau type : enregistrement contenant tous les éléments que doit
renvoyer la fonction, on est alors ramené au type de fonction vu ci-dessus (section 4.2,
p.33),
– soit en utilisant la possibilité de modifier certains des paramètres.
Dans ce deuxième cas, il n’y a pas de résultat explicitement retourné, donc il n’y a pas
de return, la traduction se fera par une fonction de type void. Il y a deux possibilités
de traduction des algorithmes de fonction, selon que certains arguments d’appel, tels que
prévus dans l’algorithme, peuvent être modifiés ou non par la fonction.

4.3.1 Les arguments ne doivent pas être modifiés par la fonction


Si les arguments dans l’algorithme ne doivent pas être modifiés par la fonction, il faut
ajouter autant de paramètre(s) lors de la traduction qu’il y a de valeur(s) à renvoyer (et
donc la traduction de l’appel à la fonction ainsi écrite aura autant d’argument(s) en plus).

⇤ Exemples
Exemple 1 : pour traduire l’algorithme de la fonction trierListeArticles(listeA,nbA) qui
renvoie le tableau d’articles listeTriee, on pourra :
– soit créer un nouveau type d’enregistrement contenant un seul champ de type
t VectArticles, et se ramener au cas précédent (section 4.2, p.33),
– soit modifier le prototype de la fonction en ajoutant un paramètre listeTriee. Les
arguments listeA et nbA ne devront pas être modifiés alors que listeTriée devra l’être.
Le prototype de la fonction trierListeArticles s’écrira :
void trierListeArticles(t_VectArticles listeA, int nbA, t_VectArticles listeTriee)
où le tableau listeTriee est passé par adresse, donc modifiable. Cette écriture peut aussi
être utilisée en C++. listeA qui est aussi un tableau pourra aussi être modifiée.

Exemple 2 : pour traduire l’algorithme de la fonction prixMinMax(nbA, listeA) qui


renvoie deux valeurs réelles, le prix minimum et le prix maximum des t Articles du tableau
de t Articles listeA passé en paramètre, on pourra :
– soit créer un nouveau type d’enregistrement ayant 2 champs réels contenant ces va-
leurs, et se ramener au cas précédent (section 4.2, p.33),
– soit modifier le prototype de la fonction en ajoutant deux paramètres réels pMin,
pMax qui devront être modifiés par la fonction, ils seront passés par référence.
Le prototype de la fonction prixMinMax s’écrira :
void prixMinMax(int nbA, t_VectArticles listeA, float & pMin, float & pMax)
où les réels pMin et pMax sont passés par référence, donc modifiables (les espaces avant et
après le & sont optionnels, pour des raisons de clarté du code, il est préférable d’en mettre
au moins un avant le &).

École Centrale de Nantes, — Algorithmique et programmation — 35


4.3. Traduction quand un tableau et/ou plusieurs valeurs sont renvoyés Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction !

⇤ Utilisation dans la fonction appelante


algorithme
listeTriee trierListeArticles(listeArticles,nbArt)
{prixMin, prixMax} prixMinMax(nbArt, listeArticles)

C++

// pas de notation particulière pour les arguments à l’appel


trierListeArticles(listeArticles, nbArt listeTriee);
prixMinMax(nbArt, listeArticles, prixMin, prixMax);

Remarque : lorsqu’il y a création d’autant de nouveaux paramètres que de valeurs à retour-


ner, le corps de l’algorithme de la fonction ne demande pas d’adaptation particulière pour
être traduit. Entre l’algorithme et sa traduction en C++ seuls le prototype de la fonction
et son appel di↵èrent.

4.3.2 Certains arguments peuvent être modifiés par la fonction


Si certains arguments peuvent être modifiés par la fonction, ces arguments seront
directement utilisés, sans création d’un nouveau paramètre. Ce cas se produit lorsque lors
de l’appel de la fonction en algorithmique, le même nom de variable est utilisé dans la partie
source et la partie cible de l’a↵ectation où est appelée la fonction (cf. ci-dessous, utilisation).

Selon le type des paramètres :


– s’il s’agit d’un tableau, comme il est automatiquement passé par adresse, il n’y a rien
à noter.
– dans les autres cas, il faut utiliser le passage par référence, noté par le symbole &.

⇤ Exemples
Exemple 1 : pour traduire l’algorithme de la fonction trierListeArticles(listeA,nbA) qui
renvoie le tableau d’articles listeTriee, s’il n’est pas nécessaire de garder l’ancien vecteur
d’articles, il est possible de modifier directement l’argument correspondant au paramètre
listeA. Dans ce cas, il n’est pas nécessaire d’ajouter un nouveau paramètre, le prototype de
la fonction trierListeArticles s’écrira :
void trierListeArticles({t_VectArticles listeA,int nbA)
où le tableau listeA est passé par adresse.
Attention : dans ce cas la traduction du corps de l’algorithme de la fonction demande en
général une adaptation, notamment au niveau des initialisations.

Exemple 2 : supposons qu’une fonction miseAJour permette de mettre à jour le prix


d’un article, d’un point de vue algorithmique cette fonction aura pour paramètre l’article
et le nouveau prix. Sa spécification algorithmique sera, avec artModifie de type t Article :
artModifie miseAJour(unArticle, unPrix)
Ici, la nouvelle valeur de l’article renvoyée par la fonction doit remplacer l’ancienne passée

École Centrale de Nantes, — Algorithmique et programmation — 36


Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction ! 4.3. Traduction quand un tableau et/ou plusieurs valeurs sont renvoyés

en argument, il n’est pas nécessaire d’ajouter un nouveau paramètre, le prototype de la


fonction miseAJour s’écrira :

void miseAJour(t_Article & unArticle, float unPrix)

⇤ Utilisation dans la fonction appelante


algorithme
listeArticles trierListeArticles(listeArticles,nbArt)
monArticle miseAJour(monArticle,monPrix) // pour un article quelconque
listeArticles(i) miseAJour(listeArticles(i),sonPrix)// pour un élément
de listeArticles

C++
trierListeArticles(listeArticles, nbArt);
miseAJour(monArticle, monPrix);
miseAJour(listeArticles[i], sonPrix);

Exemple 3 : Échange de deux valeurs entières en utilisant une sous fonction echanger
et le passage par référence de ses paramètres.
C++
#include <iostream>
using namespace std;

void echanger (int &x, int &y){


int inter;
inter = x;
x = y;
y = inter;
}

int main(){
// déclaration de deux variables entières
int a,b;
// lecture au clavier des valeurs des deux entiers
cin>>a>>b;
// écriture à l’écran de ces valeurs
cout<< a <<" "<<b<<endl;
// échange des deux valeurs
echanger(a, b);
// écriture à l’écran de ces valeurs après échange
cout<< a <<" "<<b<<endl;

return 0;
}

L’exécution de ce programme donne (en entrant au clavier les entiers 10 et 20) :

École Centrale de Nantes, — Algorithmique et programmation — 37


4.3. Traduction quand un tableau et/ou plusieurs valeurs sont renvoyés Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction !

10 20
20 10

Remarque : Pour échanger deux valeurs, au lieu d’utiliser les références aux entiers passés
en paramètres nous aurions pu utiliser des pointeurs dans la fonction echanger.
C++

#include <iostream>
using namespace std;

void echanger (int *x, int *y){


int inter;
inter = *x; // utilisation du déréférencement de pointeur avec *
*x = *y;
*y = inter;
}

int main(){
// déclaration de deux variables entières
int a,b;
// lecture au clavier des valeurs des deux entiers
cin>>a>>b;
// écriture à l’écran de ces valeurs
cout<< a <<" "<<b<<endl;
// échange des deux valeurs en passant à echanger les adresses mémoire des
variables a et b
echanger(&a, &b);
// écriture à l’écran de ces valeurs après échange
cout<< a <<" "<<b<<endl;

return 0;

L’exécution de ce programme donnerait exactement les mêmes résultats que précédemment.

4.3.3 Quelques critères pour choisir le type de traduction


L’analyse de la spécification algorithmique de la fonction et de son utilisation
permet de décider quel type de traduction est préférable.

⇤ Cas simples
Si la fonction renvoie une seule valeur de type UnType simple ou enregistrement, il faut
utiliser une fonction ayant pour type UnType.
Si la fonction, dans sa spécification algorithmique, ne renvoie pas de valeur, il faut
utiliser une fonction de type void.

École Centrale de Nantes, — Algorithmique et programmation — 38


Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction ! 4.3. Traduction quand un tableau et/ou plusieurs valeurs sont renvoyés

Attention : les arguments doivent être passés par valeur.

⇤ Cas plus complexes !


En regardant les valeurs renvoyées par la fonction :
– si la structure correspondant à l’ensemble des valeurs renvoyées est une structure qui
a un sens pertinent pour l’application, il est préférable de créer un enregistrement
correspondant, ce qui peut amener à revoir l’analyse faite du problème !
– sinon, il faut utiliser une traduction en fonction de type void et
– il faut créer un nouveau paramètre et utiliser le passage par référence (par adresse
pour un tableau)
. si une valeur renvoyée ne correspond pas à une variable déjà utilisée dans la
fonction appelante,
. si une valeur renvoyée correspond à une variable déjà utilisée dans la fonction
appelante, mais que cette variable ne doit pas être modifiée (par exemple si son
ancienne valeur reste nécessaire dans la fonction appelante),
– il faut utiliser le passage par référence (par adresse pour un tableau), sans créer de
nouveau paramètre si une valeur renvoyée correspond à une variable déjà utilisée
dans la fonction appelante et qui peut être modifiée.

Remarque : s’il y a une structure composée -tableau ou enregistrement- de grande taille


parmi les valeurs renvoyées, il faut éviter si possible de créer un nouveau paramètre, pour
limiter la place mémoire utilisée par l’ensemble des données.

École Centrale de Nantes, — Algorithmique et programmation — 39


4.4. Programmation structurée Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction !

4.4 Programmation structurée


4.4.1 Fonction principale
Rappel : la fonction principale est une fonction de type “int” dont le nom réservé est
main (cf. la présentation de la fonction principale, section 3.1.4, p. 18).
C++
int main()
{
// déclarations
...
// corps de la fonction principale
...
// fin de la fonction principale, le ’0’
// indique une fin normale
return 0;
}
Remarque : à la compilation, le type d’une fonction, son nom et la liste des types de ses
paramètres doivent être connus avant son utilisation. Si toutes les fonctions d’un programme
sont écrites dans un même fichier, la fonction principale est donc en fin de fichier. Cette dis-
position, valable pour des programmes très courts, contraire aux notions de programmation
structurée et d’analyse descendante, n’o↵re aucune possibilité d’utiliser les fonctions définies
pour l’occasion dans d’autres contextes. Elle est donc à éviter.

4.4.2 Les fichiers en-tête


Pour obtenir une plus grande indépendance des di↵érentes fonctions écrites, et donc
une plus grande facilité de réutilisation, les fonctions doivent être écrites dans des fichiers
séparés, qui doivent être compilables séparément.
Une unité de programme utilisant une fonction écrite dans un autre fichier, doit connaı̂tre
le type de la fonction et de ses paramètres lors de la compilation. Ces informations sont
contenues dans le prototype de la fonction.
Plutôt que de répéter ces informations en en-tête de toutes les unités de programmes en
ayant besoin, elles sont écrites dans un fichier à part, appelé fichier en-tête, qui est inclus
en début de chaque fichier où la fonction est utilisée.
Une bonne habitude de programmation en C/C++ est de créer un fichier en-tête,
pour chaque fichier source (contenant le texte d’un morceau de programme, pouvant
correspondre à une ou plusieurs fonctions).
L’extension utilisée pour les fichiers source est : .c (en C) ou .cxx (voire .cpp) (en C++).
L’extension utilisée pour les fichiers en-tête est : .h .

⇤ La déclaration d’une fonction :


Cette déclaration permet de donner correctement les types du résultat et des paramètres
ainsi que l’ordre et le nombre de ces derniers. Dans la ligne de déclaration, on reprend le
prototype de la fonction suivi d’un ;.

École Centrale de Nantes, — Algorithmique et programmation — 40


Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction ! 4.4. Programmation structurée

Exemples :

// pour les fonctions vues dans ce chapitre


int sommeVectEnt(t_VectEnt v,int n);
void prixMin(int nbA, t_VectArticles listeA, float &pMin, float
&pMax);
void lireEcrire(fstream &F1,fstream &F2);
Remarque : il n’est pas obligatoire de donner les noms des paramètres dans l’instruction de
déclaration d’une fonction, on peut donc écrire pour le 2ème exemple ci-dessus :
void prixMinMax(int, {\ty VectArticles}, float \&, float \&);

⇤ Le contenu des fichiers en-tête :


Un fichier en-tête contient la traduction en C/C++ des informations de la partie spéci-
fication écrite dans le dossier algorithmique.
Le fichier en-tête correspondant à un fichier source contient :
– les déclarations des constantes utilisées dans ce fichier source,
– les déclarations des types utilisés dans ce fichier source,
– les déclarations des fonctions utilisées dans ce fichier source.

Remarque : les constantes, types de données, éventuellement flots de données, utilisés dans
tous les éléments d’un programme sont définis dans le fichier en-tête correspondant à la
fonction principale (cf. exemple ci-après), ce fichier sera ensuite inclus dans tous les fichiers
contenant des fonctions utilisant tout ou partie de ces éléments.

⇤ L’inclusion du fichier en-tête :


Les fichiers source et en-tête doivent se trouver dans le même répertoire (sinon, il faut
donner le chemin d’accès au fichier). Le fichier source commence par l’ordre d’inclusion de
son fichier en-tête :

#include "MonFichier.h" // si le fichier à en-t^


ete à inclure s’appelle MonFichier.h

École Centrale de Nantes, — Algorithmique et programmation — 41


4.4. Programmation structurée Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction !

4.4.3 Instructions de compilation et fichiers ”Makefile”


L’opération de compilation peut se faire dans un environnement de développement inté-
gré (par exemple CodeBlocks), ou dans un terminal. Dans ce dernier l’utilisation des fichiers
”Makefile” est fortement conseillée.

Instructions de compilation
Les di↵érentes phases sont :
– compilation : transformer un fichier .cxx en un fichier .o
– édition des liens : rassembler un ensemble de fichiers .o en un fichier .out
Supposons que nous ayons les fichiers suivants : f1.cxx, f2.cxx, f1.h, f2.h et main.cxx. La
phase de compilation va nous permettre d’obtenir les fichiers.o correspondants aux di↵érents
fichiers .cxx :
– avec la commande
g++ -c f1.cxx
on obtient f1.o
– avec la commande
g++ -c f2.cxx
on obtient f2.o
– avec la commande
g++ -c main.cxx
on obtient main.o
Ensuite l’étape d’édition de liens va nous permettre d’obtenir un programme exécutable.
La commande
g++ -o machin.out main.o f1.o f2.o
nous permet d’obtenir l’exécutable machin.out qui sera exécuté car la commande
./machin.out

Fichiers ”Makefile”
L’ objectifs des fichiers Makefile est d’automatiser les phases de compilation et d’édition
de liens.
On a encouragé la multiplication des fichiers source, d’où l’intérêt d’automatiser la
compilation ; si on a n fichiers sources, on a également n fichiers objet et toujours un seul
exécutable. On utilise de nombreux fichiers sources pour pouvoir travailler à plusieurs sur le
même code, voire pour rendre les fichiers sources eux-mêmes plus lisibles. Un autre intérêt
est que la compilation de petits fichiers source est beaucoup plus rapide que la compilation
de très gros fichiers. Dans le cas des Makefile, on ne va recompiler que le strict nécessaire.
Principe

Construire un graphe de dépendance et le réécrire à un format particulier dans un fichier


Makefile. Soit un programme exécutable machin.out qui est construit à partir de 3 fichiers
sources f1.cxx, f2.cxx et main.cxx. On peut écrire que :

École Centrale de Nantes, — Algorithmique et programmation — 42


Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction ! 4.4. Programmation structurée

– avec f1.cxx, on construit f1.o


– avec f2.cxx on construit f2.o
– avec main.cxx, on construit main.o
– enfin, avec f1.o, f2.o et main.o, on construit machin.out
Le graphe de dépendance est l’inverse, on dit que :
– machin.out dépend de f1.o, f2.o et main.o
– f1.o dépend de f1.cxx
– f2.o dépend de f2.cxx
– main.o dépend de main.cxx
Ce graphe se traduit dans le temps. Autrement dit le graphe de dépendance, on doit
forcément avoir le membre de gauche plus récent que le ou les membres de droite.
Si le membre de gauche est plus ancien que le membre de droite, la régénération du
membre de gauche est lancée, puis le système relie le graphe de dépendance et recommence
jusqu’à ce que toutes les règles soient respectées.

Syntaxe du Makefile

# regle de generation de fichier a partir de fichier1 et fichier2


fichier: fichier1 fichier2
# commande permettant la generation, attention la commande commence apres une tabulation
g++ -...

Ces règles sont écrites dans un fichier qui s’appelle obligatoirement Makefile avec un M
majuscule et le reste en minuscules.
La régénération de la cible est faite en appelant la commande make. Le fichier commence
par la cible principale (dans notre cas, c’est toujours le fichier exécutable).
# on commence toujours par la cible principale (ici un executable)
machin.out: main.o ff1.o ff2.o
g++ -o machin.out main.o ff1.o ff2.o

# les regles de construction des .o


ff1.o: ff1.cxx
g++ -c ff1.cxx

ff2.o: ff2.cxx
g++ -c ff2.cxx

main.o: main.cxx ff1.h


g++ -c main.cxx

École Centrale de Nantes, — Algorithmique et programmation — 43


4.4. Programmation structurée Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction !

4.4.4 Exemple de programmation structurée avec des manipulations de


listes
⇤ Définition du nouveau type t listeEntier
En algorithmique, une liste d’entiers simplement chainée se définie comme :
algorithme
type
t_listeEntier : Enregistrement
entier valeur,
t_listeEntier suivant, // pointe sur l’élément suivant
Fin_enregistrement

C++
La définition de ce type se fera dans un fichier à en-tête que nous appellerons listeEntier.h
/**
* Structure de donnees de liste d’entiers
*/

struct t_ListeEntier {
// type de la donnee : un entier
int valeur;

// pointeur sur l’element suivant


t_ListeEntier* suivant;
};

⇤ Création d’une liste d’entiers


Quelles sont les opérations à e↵ectuer ?
– les listes se manipulent sous forme de pointeurs, il va donc falloir réserver de la mémoire
– a↵ecter une valeur à l’élément de liste qu’on vient de créer
– mettre l’élément suivant à 0 (en C++, on va utiliser le pointeur NULL)

École Centrale de Nantes, — Algorithmique et programmation — 44


Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction ! 4.4. Programmation structurée

fonction creeElementListe
spécification :
fonction : {nouvelElement} creeElement(x)
paramètres : entier x
résultats : t ListeEntier nouvelElement
algorithme
variables
t ListeEntier nouv
début
| nouv.valeur x
| nouv.suivant 0
| renvoyer nouv
fin

C++ dans un fichier fonctionsListes.cxx


#include <cstdlib> // pour pouvoir utiliser NULL

#include "listeEntier.h"

t_ListeEntier* creeElement(int x) {
// variable locale
t_ListeEntier *nouv;
// réservation de la mémoire
nouv = new t_ListeEntier;
// attribution de la valeur
// (*nouv).valeur = x ; juste mais pas facile
nouv->valeur = x; // notation équivalente plus simple
// élément suivant vaut null
nouv->suivant = NULL;
// renvoie d’un pointeur sur l’élément
return nouv;
}

⇤ Parcours de liste
Pour parcourir la liste, nous allons aller d’élément en élément en suivant l’élément pointé
par le champ suivant de chaque t listeEntier. En C++, nous allons utiliser une variable
locale de type t listeEntier * qui va permettre de pointer alternativement sur chaque
t listeEntier constituant la liste sans modifier le pointeur sur la tête de liste. fonction
afficherListe

spécification :
fonction : Ø afficherListe(l)
paramètres : t listeEntier l
résultats : Ø

École Centrale de Nantes, — Algorithmique et programmation — 45


4.4. Programmation structurée Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction !

algorithme

variables locales
t_listeEntier élément // élément courant qui va permettre de parcourir
la liste élément par élément

début
| élément l
| // boucle tant le dernier élément de la liste n’est pas atteint
| tant que élément existe faire
| | écrire (élément.valeur)
| | élément élément.suivant
| fin tant que
fin

C++ dans le fichier fonctionsListes.cxx à la suite de la fonction creeElementListe


//A insérer au début du fichier fonctionsListes.cxx
// pour pouvoir écrire à l’écran
#include <iostream>
using namespace std;

// puis toujours dans le fichier fonctionsListes.cxx,


// à la suite de la fonction creeElementListe

/**
* Parcourt la liste et affiche les elements un a un.
*/
void afficheListe(t_ListeEntiers *l) {
// Creation d’une variable locale t pointeur sur un t_ListeEntiers pour parcourir
// la liste pour ne pas modifier le pointeur l sur la t^
ete de la liste.
t_ListeEntier *t = l;
cout << "[ ";
while (t) {
cout << t->valeur << " " ;
t = t->suivant;
}
cout << "]" << endl;
}

⇤ Suppression d’un élément


Pour supprimer un élément de la liste, il va falloir parcourir la liste. Si il y a plusieurs
éléments de la valeur cherchée, seul le premier sera supprimé de la liste.

École Centrale de Nantes, — Algorithmique et programmation — 46


Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction ! 4.4. Programmation structurée

fonction supprimeElement

spécification :
fonction : nouvL supprimeElement(l, val)
paramètres : t listeEntier l
entier val //valeur de l’élément à supprimer
résultats : t listeEntier nouvL
algorithme

variables locales
t_listeEntier element // élément courant qui va permettre de parcourir
la liste élément par élément
t_listeEntier precedent
booléen trouvé

début
| si ( l non vide ) alors
| | trouvé faux
| | nouvL l
| | element l
| | // cas particulier : le premier élément doit ^
etre supprimé
| | si ( element.valeur = val ) alors
| | | nouvL nouvL.suivant
| | sinon
| | | precedent element
| | | element element.suivant
| | | // boucle tant le dernier élément de la liste n’est pas atteint
| | | tant que element existe et non trouvé faire
| | | | si ( element.valeur = val ) alors
| | | | | precedent.suivant element.suivant
| | | | | trouvé vrai
| | | | sinon
| | | | | precedent element
| | | | | element element.suivant
| | | | fin si
| | | fin tant que
| | fin si
| sinon
| | nouvL rien
| fin si
| renvoyer nouvL
fin

École Centrale de Nantes, — Algorithmique et programmation — 47


4.4. Programmation structurée Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction !

C++ dans le fichier fonctionsListes.cxx à la suite de la fonction afficheListe


/**
* Supprime le premier element de valeur val dans la liste l. Il ne se passe rien si
* l’element n’existe pas.
*/
t_ListeEntier* supprimeElementListe(t_ListeEntier *l, int val) {
t_ListeEntier *t,*prec; // utilisation de pointeurs pour parcourir la liste
if(l){
// cas particulier : premier élément
if (l->valeur == val) {
t = l->suivant;
delete l; // libération de la mémoire
return t;
}else {
t = l->suivant;
prec = l;
while (t) {
if (t->valeur == val) {
prec->suivant = t->suivant;
delete t;
return l;
}
prec = t;
t = t->suivant;
}
}
// pas trouvé, on retourne la liste sans changement
return l;
}else{
return NULL;
}
}

⇤ Fonction principale et fichier à en-tête


Nous complétons le fichier à en-tête listeEntier.h avec les prototypes des fonctions définies
dans fonctionsListes.cxx.
C++ fichier listeEntier.h
/**
* structure de donnees de liste d’entiers
*/

struct t_ListeEntier {
// type de la donnée : un entier
int valeur;

// pointeur sur l’élement suivant


t_ListeEntier* suivant;
};

École Centrale de Nantes, — Algorithmique et programmation — 48


Chapitre 4. Programmes et sous-programmes C/C++ : tout est fonction ! 4.4. Programmation structurée

t_ListeEntier* creeElement(int x);

void afficheListe(t_ListeEntier *l);

t_ListeEntier* supprimeElementListe(t_ListeEntier *l, int val);


et nous écrivons un programme principal dans un fichier mainListe.cxx
C++
/**
* Programme principal de manipulation de listes
*/

#include <stdlib.h>
#include <iostream>
using namespace std;

#include "listeEntier.h"

int main() {
t_ListeEntier * l1 = creeElement(3);
t_ListeEntier * l2 = creeElement(5);
t_ListeEntier * l3 = creeElement(7);

l1->suivant = l2;
l2->suivant = l3;

afficheListe(l1);

l1 = supprimeElementListe(l1, 5);

afficheListe(l1);

return 0;
}
L’exécution de ce programme donne l’affichage suivant :
[ 3 5 7 ]
[ 3 7 ]

École Centrale de Nantes, — Algorithmique et programmation — 49


Deuxième partie

GUIDE POUR LES TRAVAUX


PRATIQUES

École Centrale de Nantes, — Algorithmique et programmation — 50


Chapitre 1

Rapport de travaux pratiques

1.1 Composition du dossier informatique


Le rapport de travaux pratiques regroupe tous les éléments qui permettent de résoudre
à l’aide de l’outil informatique le problème posé en TP. L’objectif d’un tel dossier est :
– qu’une personne voulant résoudre ce même problème puisse utiliser le programme
écrit,
– qu’une personne devant amender le programme écrit puisse le faire.

Il concrétise les di↵érentes étapes de résolution informatique d’un problème :


– analyse du problème donné, énoncé d’un procédé de traitement,
– traduction de ce procédé sous forme d’algorithmes,
– traduction des algorithmes dans le langage utilisé (C/C++ ou autre),
– analyse du fonctionnement du programme et des résultats obtenus.

Pour cela le rendu attendu d’un TP comporte 3 parties :


– une partie algorithmique présentant et expliquant les algorithmes,
– un listage des fichiers contenant le code (C/C++ ou autre) qui sera rendu à part,
– une partie jeux d’essai – tests, qui illustre la façon dont le programme fonctionne et
ses limites.

1.2 Partie algorithmique


La partie algorithmique comporte autant de dossiers algorithmiques qu’il y a de fonctions
pour résoudre le problème posé. Un dossier algorithmique doit présenter 3 parties :

1.2.1 Problème
La partie problème a un but documentaire, elle doit permettre à une personne qui prend
connaissance du dossier de savoir à quoi sert l’algorithme. Cette partie rappelle donc l’énoncé
du problème à traiter (le but du programme), elle précise les hypothèses du problème et
définit les résultats attendus.

École Centrale de Nantes, — Algorithmique et programmation — 51


1.2. Partie algorithmique Chapitre 1. Rapport de travaux pratiques

1.2.2 Spécification
La partie spécification comporte le nom par lequel la fonction dont on fait le dossier
sera appelée ainsi que la liste des paramètres et des résultats de cette fonction, avec leurs
types et leurs rôles. C’est la partie « visible » de la fonction pour les autres fonctions. Elle
contient l’ensemble des informations nécessaires pour utiliser cette fonction.
S’il s’agit de la fonction principale, la partie spécification comporte la description des
types de données particuliers utilisés (matrice, enregistrement, . . . ) dans l’ensemble des fonc-
tions nécessaires pour résoudre le problème principal. Si aucun type de données particulier
n’est nécessaire, la partie spécification de la fonction principale est inutile.

1.2.3 Algorithme
Cette partie commence par la description des objets utilisés localement dans la fonction
(principales variables locales) : types, noms et commentaires sur leur rôle.
Puis l’algorithme détaille l’ensemble des instructions simples ou composées à exécuter
sur les objets précédemment décrits.
A des fins de lisibilité, l’ensemble de ces instructions, écrites entre les mots début et
fin devra être écrit sur une seule page de format A4. Si cela est impossible, certaines
instructions élémentaires seront regroupées sous la forme de fonctions clairement nommées,
accompagnées d’un dossier algorithmique.

1.2.4 Exemple de dossier algorithmique d’une fonction principale sans


appel d’une fonction secondaire
Voici un exemple où aucun type de données autre que les types simples n’est utilisé et
où il n’y a pas de paramètres à déclarer : la partie spécification est inutile.
fonction principale
sommeFile
problème : lire une file d’entiers terminée par 999, et restituer la somme des nombres lus,
hormis 999.
algorithme
variables
entiers n, // élément courant de la file
s // résultat : somme des éléments de la file

École Centrale de Nantes, — Algorithmique et programmation — 52


Chapitre 1. Rapport de travaux pratiques 1.2. Partie algorithmique

début
| // initialisations
| s 0
| n lire ()
| tant que n6=999 faire
| | // ajouter n à s
| | s s + n
| | // lire l’élément suivant de la file
| | n lire ()
| fin tant que
| écrire (s)
| renvoyer s
fin

1.2.5 Exemples d’algorithmes de fonctions


fonction plusGrand
problème : recherche du plus grand parmi 3 nombres.
spécification :
fonction : w plusGrand (x, y, z)
paramètres : réels x, y, z // nombres à tester
résultats : réel w // le plus grand des 3 nombres
algorithme
début
| // recherche du plus grand de x et y
| w plusGd2 (x,y)
| // Recherche du plus grand de w et z
| w plusGd2 (w,z)
| // on aurait pu écrire directement : w plusGd2(plusGd2(x,y),z)
| renvoyer w
fin

fonction plusGd2 (u, v)


problème : recherche du plus grand parmi 2 nombres
spécification :
fonction : plusGd2 (u,v)
paramètres : réels u, v // nombres à comparer
résultats : réel w // le plus grand de u et v

École Centrale de Nantes, — Algorithmique et programmation — 53


1.3. Fichiers contenant le code de programmation Chapitre 1. Rapport de travaux pratiques

algorithme
début
| si ( u v ) alors
| | w u
| sinon
| | w v
| fin si
| renvoyer w
fin

1.3 Fichiers contenant le code de programmation


Il est indispensable d’écrire avec soin l’algorithme avant de passer à sa
traduction dans un langage de programmation.

1.3.1 En-tête de présentation


Les fichiers écrits commencent par un en-tête de quelques lignes de commentaires com-
portant :
– les auteurs du programme, la date,
– le but des fonctions écrites,
– les fichiers où sont écrites les di↵érentes fonctions appelées par celles-ci,
– éventuellement les compilations nécessaires et la commande d’édition de liens permet-
tant de relier l’ensemble.

1.3.2 Présentation des fonctions


Une bonne présentation typographique accroı̂t la lisibilité du code :
– aligner verticalement les début et fin de structures (par exemple les if else, et acco-
lades ouvrantes et fermantes en C/C++), cf. les exemples donnés dans ce document,
– aérer le programme en séparant par exemple l’en-tête, les déclarations, les initialisa-
tions... par des lignes vides.

Les seules instructions à utiliser sont celles données dans la partie langage (C/C++). Ce
sont des traductions des structures algorithmiques vues dans la partie algorithmique.

Toute utilisation d’instruction ou de structure non citée dans ce polycopié est


proscrite.

1.3.3 Commentaires
Les commentaires sont nécessaires pour :
– préciser le rôle des paramètres, résultats et variables,
– expliquer les idées sous-jacentes ou les points délicats des algorithmes,

École Centrale de Nantes, — Algorithmique et programmation — 54


Chapitre 1. Rapport de travaux pratiques 1.4. Résultats

– mettre en évidence les di↵érentes étapes des fonctions.

On doit retrouver les commentaires utilisés dans les algorithmes. Par contre, il faut éliminer
les commentaires qui ne feraient que paraphraser le code et donc l’encombrer.

1.3.4 Choix des identificateurs de variables


Il est conseillé d’employer systématiquement des identificateurs ayant un sens intuitif
(mnémotechnique) ou correspondant à une convention en accord avec leur usage dans le
programme (mathématique, physique, ...).

1.4 Résultats
Cette partie est composée de listages de di↵érents tests et jeux d’essai, ainsi que les
analyses et commentaires sur les résultats obtenus.

1.4.1 Jeux d’essai


Ils doivent être choisis de manière pertinente, de façon à montrer le bon fonctionnement
du programme. Ils doivent tester les possibilités du programme, en traitant les situations
normales et les cas particuliers.
Exemples :

– pour un traitement de file, tester quelques exemples, notamment le cas éventuel où la
file est vide,
– pour un choix donné à l’utilisateur, donner un exemple où l’utilisateur donne une
réponse non proposée,
– pour le calcul d’une limite d’une suite numérique, donner un exemple où il y a conver-
gence, un exemple où la convergence n’est pas obtenue.

1.4.2 Analyse et commentaires sur les résultats


Ils doivent expliquer l’intérêt de chaque jeu d’essai, en montrant quelle particularité du
programme ce jeu d’essai met en évidence, et de quelle façon s’exécute alors le programme.
Les jeux d’essai sont induits par l’analyse qui a été faite du problème, il est bon d’y
penser en écrivant les algorithmes.

École Centrale de Nantes, — Algorithmique et programmation — 55


Chapitre 2

Exemple de rapport

Cet exemple reprend le problème analysé chapitre Analyse descendante - Fonctions du


cours d’algorithmique.

2.1 Dossier algorithmique


Soit une liste d’articles donnés avec leurs noms (libellés), références et prix unitaires.
Trier cette liste en ordre croissant de références et indiquer les prix minimum et maximum
de l’ensemble de ces articles.

2.1.1 Algorithmes
fonction principale

problème : Etant donnée une liste d’articles avec le nom, la référence et le prix unitaire,
l’afficher triée en ordre croissant de références et donner les valeurs minimum et maximum
des prix.
types
t_Article : Enregistrement
entier : reference,
chaine : libelle,
réel : prix
Fin_enregistrement
t_VectArticles : vecteur de t_Article

algorithme

début
| // obtenir les données
| {nA,listeArticles} lire ()
| // traiter les données
| listeArticles trierListeArticles(nA,listeArticles)

École Centrale de Nantes, — Algorithmique et programmation — 56


Chapitre 2. Exemple de rapport 2.1. Dossier algorithmique

| {prixMin,prixMax} prixMinMax(nA,listeArticles)
| // donner les résultats
| écrire (nA, listeTriee, prixMin, prixMax)
fin

fonction trierListeArticles

problème : Ranger dans un nouveau vecteur les éléments d’un vecteur d’articles, en
les triant suivant l’ordre croissant du champ reference.

spécification :
fonction : listeTriee trierListeArticles(nbArt,listeArticles)
paramètres : entier nbArt
t VectArticles listeArticles
résultats : t VectArticles listeTriee
algorithme
début
| // initialisation
| listeTriee listeArticles
| // tri des articles
| pour i 1 à NbArt-1 faire
| | // recherche de l’indice de l’article de plus petite reference
| | min i
| | pour j i+1 à nbArt faire
| | | si ( listeTriee[j].reference < listeTriee[min].reference )
alors
| | | | min j
| | | fin si
| | fin pour
| | // permutation éventuelle des articles d’indices i et min
| | si ( min 6= i ) alors
| | | unArticle listeTriee[i]
| | | listeTriee[i] listeTriee[min]
| | | listeTriee[min] unArticle
| | fin si
| fin pour
| // renvoi des résultats
| renvoyer listeTriee
fin
fonction prixMinMax
problème : Chercher les valeurs minimum et maximum des prix des articles
spécification :
fonction : {prixMin,prixMax} prixMinMax(nbArt,listeArticles)
paramètres : entier nbArt
t VectArticles listeArticles
résultats : réels prixMin, prixMax

École Centrale de Nantes, — Algorithmique et programmation — 57


2.1. Dossier algorithmique Chapitre 2. Exemple de rapport

algorithme
début
| // recherche du min et du max
| iMin 1 ; iMax 1
| prixMin listeArticles[1].prix ; prixMax prixMin
| pour i 2 à nbArt faire
| | si ( listeArticles[i].prix < prixMin ) alors
| | | iMin i ; prixMin listeArticles[i].prix
| | fin si
| | si ( listeArticles[i].prix > prixMax ) alors
| | | iMax i ; prixMax listeArticles[i].prix
| | fin si
| fin pour
| // renvoi des résultats
| renvoyer prixMin, prixMax
fin

2.1.2 Traduction en C/C++


⇤ Fichier en-tête TypesArticles.h contenant les définitions de constantes
et de types utilisés dans les di↵érentes fonctions :

/*==========================================================================
Equipe Pedagogique d’Algorithmique et Programmation
Traitement d’une liste d’articles
-----------------------------------------------------------------------------
Fichier en-tete contenant la description des types utilises
Nom du fichier : TypesArticles.h
===========================================================================*/
# include <string>

/* Definition des constantes */


const int MAXARTICLES = 100 ; // au plus 100 articles, indices de 0 à 99

// t_Article est un enregistrement ayant 3 champs


struct t_Article
{
int reference;
string libelle;
float prix;
};

// t_VectArticles est un vecteur de t_Article


typedef t_Article t_VectArticles[MAXARTICLES];

École Centrale de Nantes, — Algorithmique et programmation — 58


Chapitre 2. Exemple de rapport 2.1. Dossier algorithmique

⇤ Fichier en-tête FonctionsArticles.h contenant la déclaration des fonc-


tions pour manipuler les t Articles :

/*==============================================================================
Equipe Pedagogique d’Algorithmique et Programmation
Traitement d’une liste d’articles
---------------------------------------------------------------------------------
Declaration des fonctions de manipulation des t_Articles
Nom du fichier : FonctionsArticles.h
================================================================================*/

void trierListeArticles(int nA, t_VectArticles lA);

void prixMinMax(int nA,t_VectArticles lA, float * pMin, float * pMax);


⇤ Fichier TtArticles.cxx contenant la fonction principale :

/*==============================================================================
Equipe Pedagogique d’Algorithmique et Programmation
Traitement d’une liste d’articles
---------------------------------------------------------------------------------
Fonction principale :
Etant donnee une liste d’articles avec le nom, la reference et le prix unitaire,
les redonner tries en ordre croissant de references et donner les valeurs
minimum et maximum des prix. Utilisation d’une fonction de tri et d’une fonction
donnant les valeurs cherchees.

Nom du fichier : TtArticles.cxx


Compilation : g++ -c TtArticles.cxx
Edition de liens : g++ -o TtArticles.out TtArticles.o TrierArticles.o PrixMinMax.o
================================================================================*/
/* Directives d’inclusion de fichiers */
# include <iostream> /* pour la lecture du nom du fichier de donnees
et l’ecriture des resultats */
# include <fstream> /* pour l’utilisation du fichier de donnees */
# include <string> /* pour l’utilisation du type string */

using namespace std;

# include "TypesArticles.h" /* definition des types utilises */


# include "FonctionsArticles.h" /* declaration des fonctions trierListeArticles et
prixMinMax */

int main()
{
int nbArt;
t_VectArticles listeArticles;
float prixMin, prixMax ;
int i; // indice necessaire pour la lecture des articles
string nomFichier ;

École Centrale de Nantes, — Algorithmique et programmation — 59


2.1. Dossier algorithmique Chapitre 2. Exemple de rapport

fstream F;

/* obtenir les donnees : ici elles sont dans un fichier dont le nom
est demande a l’utilisateur */
cout<<"Nom du fichier ? "; cin >>nomFichier;
F.open(nomFichier.c_str(), ios::in);
//lire le nombre d’articles dans le fichier
F>>nbArt;

// lire la suite d’articles


for(i=0;i<nbArt;i=i+1)
{
// lecture des champs dans l’ordre ou ils sont ecrits dans le fichier !
F>>listeArticles[i].reference>>listeArticles[i].libelle>>listeArticles[i].prix;
}
// fermer le fichier
F.close();
// traiter les données
trierListeArticles(nbArt,listeArticles);
prixMinMax(nbArt,listeArticles,&prixMin,&prixMax);
cout<<"Liste des "<<nbArt<<" articles, tri\’es par r\’ef\’erence "<<endl;
for(i=0;i<nbArt;i=i+1)
{
cout<<listeArticles[i].reference<<" "<<listeArticles[i].libelle;
cout<<" "<<listeArticles[i].prix<<endl;
}
cout<<endl<<"Le prix maximum est : "<<prixMax;
cout<< " et le prix minimum est : "<<prixMin<<endl;
return 0;
} // fin de la fonction de traitement d’articles

École Centrale de Nantes, — Algorithmique et programmation — 60


Chapitre 2. Exemple de rapport 2.1. Dossier algorithmique

⇤ Fichier FonctionsArticles.cxx contenant les fonctions TrierArticles et


PrixMinMax :

/*==============================================================================
Equipe Pedagogique d’Algorithmique et Programmation
Traitement d’une liste d’articles
================================================================================*/
/* Directives d’inclusion de fichiers */
# include <string>
using namespace std;
# include "TypesArticles.h" /* definition des types utilises */
# include "FonctionsArticles.h" /* declaration de la fonction trierListeArticles */

/*
Fonction TrierArticles :
Etant donnee une liste d’articles avec le nom, la reference et le prix unitaire,
trier cette liste en ordre croissant de references. Le tri utilise est un tri
par extraction du minimum.

Nom du fichier : TrierArticles.cxx


Compilation : g++ -c TrierArticles.cxx
*/
void trierListeArticles(int nA, t_VectArticles lA)
{
int i,j,min;
t_Article unArticle;
// remarque : pas d’initialisation de listeTriee qui est inutile ici
for(i=0;i<nA-1;i=i+1)
{
// recherche de l’indice de l’article de plus petite reference
min = i;
for(j=i+1;j<nA;j=j+1)
{
if (lA[j].reference < lA[min].reference)
{
min = j;
}
}
// permutation eventuelle des articles d’indice i et min
if (i!= min)
{
unArticle = lA[i];
lA[i] = lA[min];
lA[min] = unArticle ;
}
}
}// fin de la fonction, pas de return : la fonction est de type void

École Centrale de Nantes, — Algorithmique et programmation — 61


2.1. Dossier algorithmique Chapitre 2. Exemple de rapport

/*
Fonction PrixMinMax :
Etant donnee une liste d’articles avec le nom, la reference et le prix unitaire,
trouver les valeurs minimum et maximum des prix. C’est un traitement de file.
Le nombre d’articles etant connu, utilisation d’une structure iterative "pour".

Nom du fichier : PrixMinMax.cxx


Compilation : g++ -c PrixMinMax.cxx
*/
void prixMinMax(int nA,t_VectArticles lA, float * pMin, float * pMax)
{
int i, iMin, iMax; //indices des articles de prix Min et prix Max
iMin = 1; iMax = 1;
*pMin = lA[0].prix; // attention : les indices commencent a 0 dans lA
*pMax = *pMin;
for(i=1;i<nA;i=i+1)
{
if (lA[i].prix < *pMin)
{
iMin = i; *pMin = lA[i].prix;
}
if (lA[i].prix > *pMax)
{
iMax = i; *pMax = lA[i].prix;
}
}
} // pas de return : fonction de type void

École Centrale de Nantes, — Algorithmique et programmation — 62


Chapitre 2. Exemple de rapport 2.1. Dossier algorithmique

⇤ Compilation et édition de liens, sur les PC-système Linux :


Les di↵érents éléments du code, écrits dans des fichiers séparés, doivent être compilés
séparément, puis reliés entre eux par édition de liens pour créer un fichier exécutable, appelé
ici TtArticles.out.
> g++ -c TtArticles.cxx
> g++ -c FonctionsArticles.cxx

> g++ -o TtArticles.out TtArticles.o FonctionsArticles.o

Remarques :
– L’ordre des compilations est indi↵érent,
– La liste des noms suivant la commande d’édition de liens doit commencer, par le nom
du fichier contenant la fonction principale (compilé).
# Fichier Makefile du programme de traitement d’Articles
# Les commentaires sont notes par un # en debut de ligne
# all : executer toutes les commandes ci-apres necessaires pour obtenir le fichier
# executable TtArticles.out

all : TtArticles.out

#----------------------------------
# Directives de compilation
#----------------------------------
# Donner la liste des fichiers dont depend la construction du fichier TtArticles.o :
# ce sont tous les fichiers inclus (hors ceux de la bibliotheque) et TtArticles.cxx
# La compilation ne sera faite que si l’un au moins de ces fichiers a ete modifie
# !! tabulation avant les commandes et / en fin de ligne si une commande
# prend plusieurs lignes
TtArticles.o : TtArticles.cxx TypesArticles.h FonctionsArticles.h
g++ -c TtArticles.cxx

# Liste des fichiers dont depend la construction du fichier FonctionsArticles.o


# ici un seul fichier inclus, deux "dependances"
# (une modification dans TypesArticles.h obligera a refaire la compilation
# meme s’il n’y a pas de modification faite dans FonctionsArticles.cxx et vice-versa)
# et commande de compilation
FonctionsArticles.o : FonctionsArticles.cxx TypesArticles.h
g++ -c FonctionsArticles.cxx

#--------------------------------------
# Directives d’edition des liens
#--------------------------------------
# Liste des fichiers dont depend la construction du fichier Exemple.out
# tous les .o obtenus par compilation des differentes unites du programme
# et commande d’edition de liens
TtArticles.out : TtArticles.o FonctionsArticles.o
g++ -o TtArticles.out TtArticles.o FonctionsArticles.o

# NB : en cas d’utilisation de bibliotheque specifique, il faudrait la noter

École Centrale de Nantes, — Algorithmique et programmation — 63


2.1. Dossier algorithmique Chapitre 2. Exemple de rapport

# dans la liste des dependances et dans la commande d’edition de liens

# Fin du fichier Makefile de TtArticles.out

École Centrale de Nantes, — Algorithmique et programmation — 64


Troisième partie

ANNEXE

École Centrale de Nantes, — Algorithmique et programmation — 65


Correspondance Algorithme & C++
S TRUCTURES DE DONNÉES

Types de données (simples) Types de données (composés)


booléen bool types
entier int Tableaux
réel float ou double t_VectEnt : vecteur d’entiers typedef int
caractère char t_VectEnt[MAX] ;
t_MatReels : matrice de réels typedef float
Données simples t_MatReels[MAX][MAX] ;
variables Enregistrements
entiers nb1, nb2, somme int nb1, nb2, somme ; t_Article : enregistrement # include<string>
réel moyenne float moyenne ; entier : référence using namespace std ;
Chaine_de_caractère : libellé struct t_Article {
constantes réel : prix int reference ;
réel PI const float PI=3.15 ; fin enregistrement string libelle ;
entier MAX const int MAX=10 ; float prix ;
caractère OUI const char OUI=’o’ ; };

Opérateurs Données composées


<  6= = > < <= != == >= > t_VectEnt vect t_VectEnt vect ;
et ou non && || ! t_MatReels matReels t_MatReels matReels ;
t_Article artCour t_Article artCour ;

S TRUCTURES ALGORITHMIQUES

Structures de choix
Instructions
Choix alternatif
Affectation
si nb1<nb2 alors if (nb1<nb2) {
Sx sin(A + 3 ⇤ x) Sx=sin(A+3*x) ;
écrire (nb2) cout<<nb2<<endl ;
matReels(nb1, nb2) 1 matReels[nb1][nb2]=1 ;
sinon } else {
artCour.reference 123 artCour.reference=123 ;
écrire (nb1) cout<<nb1<<endl ;
Lecture/Ecriture
fin si }
#include <iostream>
using namespace std ;
Choix sélectif
nb1 lire ( ) cin>>nb1 ;
artCour lire ( ) cin>>artCour.reference choix selon : switch (var) {
>>artCour.libelle var = 1 : case 1 :
>>artCour.prix ; écrire (“positif”) cout<<“positif” ;
écrire (nb1, nb2) cout<<“nb1 :”<<nb1 break ;
<<“nb2 :”<<nb2 ; var = -1 : case -1 :
écrire (vect) for(i=0 ; i<MAX ; i++){ écrire (“négatif”) cout<<“négatif” ;
cout<<vect[i]<<endl ; break ;
} autre : default :
écrire (“nul”) cout<<“nul” ;
fin choix selon }
Commentaires
/* commentaire C
Structures répétitives
/ commentaire / sur plusieurs lignes*/
// commentaire C++
Tant que . . .Faire
Structure générale nb1 lire ( ) cin>>nb1 ;
tant que nb1>0 faire while (nb1>0) {
problème . . . /* Explications somme somme+nb1 somme=somme+nb1 ;
sur le programme */ nb1 lire ( ) cin>>nb1 ;
spécification . . . /* inclusions */ fin tant que }
#include <...>
types . . . typedef ...
constantes . . . const ... Pour . . .Faire
algorithme int main() { pour i 0 à MAX faire for (i=0 ;i<=MAX ;i=i+1){
somme somme+vect(i) somme=somme+vect[i] ;
début //début du programme
fin pour }
corps de l’algorithme //corps du programme
fin } //fin du programme

École Centrale de Nantes, — Algorithmique et programmation — 66

Vous aimerez peut-être aussi