Partie 1.cours Programmation C++ - 072434
Partie 1.cours Programmation C++ - 072434
Partie 1.cours Programmation C++ - 072434
C++
1
Table des matières
I. Qu'est-ce que le C++ ? ........................................................................................................ 5
I.1. Rôle des programmes .................................................................................................. 5
I.2. Les langages de programmation .................................................................................. 6
I.3. Le C++ face aux autres langages ................................................................................. 7
I.3.1. Le C++ : langage de haut ou de bas niveau ? ....................................................... 7
I.4. La petite histoire du C++ ........................................................................................... 10
I.4.1. De l'Algol au C++ .............................................................................................. 10
I.4.2. Le concepteur ..................................................................................................... 11
En résumé ......................................................................................................................... 11
II. Installez les logiciels nécessaires pour programmer ........................................................ 12
II.1 Les outils nécessaires au programmeur ..................................................................... 12
II.1.1. Les projets ......................................................................................................... 13
II.1.2. Choisissez votre IDE ......................................................................................... 13
II.2. Visual C++ (Windows seulement) ........................................................................ 14
II.2.1 Installation .......................................................................................................... 16
II.2.2. Créez un nouveau projet .................................................................................... 16
II.3. Ajoutez un nouveau fichier source........................................................................ 19
II.4. La fenêtre principale de Visual ............................................................................. 20
En résumé ......................................................................................................................... 22
III. Créez votre premier programme ...................................................................................... 23
III.1. Le monde merveilleux de la console ........................................................................ 23
III.2. Les programmes graphiques ................................................................................. 23
III.3. Les programmes console ....................................................................................... 24
III.4. Notre première cible : les programmes console .................................................... 25
IV. Création et lancement d'un premier projet ................................................................ 25
IV.1. Création d'un projet ............................................................................................... 26
IV.2. Lancement du programme .................................................................................... 27
V. Explications sur ce premier code source ....................................................................... 29
VI. Commentez et mettez en forme vos programmes ! ................................................... 33
VI.1 Les différents types de commentaires ................................................................... 33
VI.2. Mettez votre code en forme .................................................................................. 35
VII. Définissez les variables pour utiliser la mémoire ...................................................... 36
2
VII.1. Qu'est-ce qu'une variable ? ................................................................................ 36
VII.3. Les types de variables ....................................................................................... 38
VII.4. Déclarez une variable ........................................................................................ 39
VII.4.1. Le cas des strings................................................................................................ 43
VII.4.2. Une astuce pour gagner de la place ................................................................... 44
VII.5. Déclarez sans initialiser ........................................................................................ 44
VIII. Affichez la valeur d'une variable .............................................................................. 46
Les références ................................................................................................................... 48
IV. Implémentez les opérations d'une calculatrice ................................................................. 51
IV.1. Demandez des informations à l'utilisateur ................................................................. 51
IV.1.1. D'autres variables ................................................................................................... 53
IV.1.2. Le problème des espaces .................................................................................... 54
IV.2. Modifiez des variables ............................................................................................... 56
IV.2.2. Une vraie calculatrice de base ! .......................................................................... 58
IV.3. Les constantes ............................................................................................................ 60
IV.3.1. Déclarez une constante ....................................................................................... 61
IV.4. Un premier exercice................................................................................................... 61
IV.4. Les raccourcis ............................................................................................................ 64
IV.4.1. L'incrémentation ................................................................................................. 65
IV.4.2. La décrémentation .............................................................................................. 65
IV.4.3. Les autres opérations .......................................................................................... 66
IV.5. Encore plus de maths ! ............................................................................................... 67
IV.5.1. Quelques autres fonctions présentes dans cmath ............................................... 68
IV.5.2. Le cas de la fonction puissance .......................................................................... 69
V. Utilisez les structures de contrôle ..................................................................................... 72
Les conditions .................................................................................................................. 72
Booléens et combinaisons de conditions .......................................................................... 80
Les boucles ....................................................................................................................... 82
Découpez votre programme en fonctions ............................................................................. 88
Créez et utilisez une fonction ........................................................................................... 88
Quelques exemples ........................................................................................................... 95
Passage par valeur et passage par référence ................................................................... 100
Utilisez plusieurs fichiers ............................................................................................... 106
3
Des valeurs par défaut pour les arguments ..................................................................... 115
Manipulez les tableaux ....................................................................................................... 121
Les tableaux statiques ..................................................................................................... 121
Les tableaux dynamiques ............................................................................................... 129
Les tableaux multi-dimensionnels .................................................................................. 136
Les strings comme tableaux ........................................................................................... 139
Lisez et modifiez des fichiers ......................................................................................... 142
Écrivez dans un fichier ................................................................................................ 142
Lisez un fichier ............................................................................................................. 146
Quelques astuces ........................................................................................................ 150
TP : le mot mystère ......................................................................................................... 156
Préparatifs et conseils................................................................................................. 156
Correction ..................................................................................................................... 161
Allez plus loin ............................................................................................................... 165
Déclarez les pointeurs .................................................................................................... 167
Une question d'adresse .............................................................................................. 167
Les pointeurs ................................................................................................................ 170
L'allocation dynamique ............................................................................................... 176
Quand utiliser des pointeurs ...................................................................................... 180
4
I. Qu'est-ce que le C++ ?
L'informatique vous passionne et vous aimeriez apprendre à programmer ? Et pourquoi pas
après tout ! La programmation peut sembler difficile au premier abord mais c'est un univers
beaucoup plus accessible qu'il n'y paraît !
Vous vous demandez sûrement par où commencer, si le C++ est fait pour vous, s'il n'est pas
préférable de démarrer avec un autre langage. Vous vous demandez si vous allez pouvoir faire
tout ce que vous voulez, quelles sont les forces et les faiblesses du C++…
Les programmes sont à la base de l'informatique. Ce sont eux qui vous permettent d'exécuter
des actions sur votre ordinateur.
Prenons par exemple la figure suivante qui représente une capture d'écran de mon ordinateur.
On y distingue 3 fenêtres correspondant à 3 programmes différents. Du premier plan à
l'arrière-plan :
• le navigateur web Google Chrome, qui permet de consulter des sites web ;
• l'explorateur de fichiers, qui permet de gérer les fichiers sur son ordinateur ;
5
• le traitement de texte Microsoft Word, qui permet de rédiger lettres et documents.
Comme vous le voyez, chacun de ces programmes est conçu dans un but précis. Chacun d'eux
correspond à un programme différent.
Moi aussi je veux créer des programmes ! Comment dois-je m'y prendre ?
Tout d'abord, commencez par mesurer vos ambitions. Un jeu tel que Starcraft II nécessite des
dizaines de développeurs à plein temps, pendant plusieurs années. Ne vous mettez donc pas
en tête des objectifs trop difficiles à atteindre.
En revanche, si vous suivez ce cours, vous aurez de solides bases pour développer des
programmes. Vous saurez créer des programmes dotés de fenêtres. Avec un peu de travail
supplémentaire, vous pourrez même créer des jeux 2D et 3D si vous le désirez. Bref, avec le
temps et à force de persévérance, vous pourrez aller loin.
Alors oui, je n'oublie pas votre question : vous vous demandez comment réaliser des
programmes. La programmation est un univers très riche. On utilise des langages de
programmation qui permettent d'expliquer à l'ordinateur ce qu'il doit faire. Voyons plus en
détail ce que sont les langages de programmation.
Votre ordinateur est une machine étonnante et complexe. À la base, il ne comprend qu'un
langage très simple constitué de 0 et de 1. Ainsi, un message tel que celui-ci :
1010010010100011010101001010111010100011010010
Pour se simplifier la vie, les informaticiens ont créé des langages intermédiaires, plus simples
que le binaire. Il existe aujourd'hui des centaines de langages de programmation. Pour vous
faire une idée, vous pouvez consulter le site :
https://fr.wikipedia.org/wiki/Liste_des_langages_de_programmation.
Tous les langages de programmation ont le même but : vous permettre de parler à l'ordinateur
plus simplement qu'en binaire. Voici comment cela fonctionne :
6
La compilation
Le fameux « programme de traduction » s'appelle en réalité le compilateur. C'est un outil
indispensable. Il vous permet de transformer votre code, écrit dans un langage de
programmation, en un vrai programme exécutable.
La compilation en détail
Voilà ce que je vous demande de retenir pour le moment : ce n'est pas bien compliqué mais
c'est la base à connaître absolument !
Mais justement, comment dois-je faire pour choisir le langage de programmation que je vais
utiliser ? Tu as dit toi-même qu'il en existe des centaines !
Lequel est le meilleur ? Est-ce que le C++ est un bon choix ?
Les programmeurs (aussi appelés développeurs) connaissent en général plusieurs langages de
programmation et non pas un seul. On se concentre rarement sur un seul langage de
programmation.
Bien entendu, il faut bien commencer par l'un d'eux. La bonne nouvelle, c'est que vous
pouvez commencer par celui que vous voulez ! Les principes des langages sont souvent les
mêmes, vous ne serez pas trop dépaysés d'un langage à l'autre.
Néanmoins, voyons plus en détail ce qui caractérise le C++ par rapport aux autres langages de
programmation… Et bien oui, c'est un cours de C++ ne l'oubliez pas !
Que vaut le C++ par rapport aux autres langages ?
Parmi les centaines de langages de programmation qui existent, certains sont plus populaires
que d'autres. Sans aucun doute, le C++ est un langage très populaire. Des sites
comme LangPop.com tiennent à jour un classement des langages les plus couramment
utilisés, si cette information vous intéresse. Comme vous pourrez le constater, le C, le Java et
le C++ occupent régulièrement le haut du classement.
7
La question est : faut-il choisir un langage parce qu'il est populaire ? Il existe des langages
très intéressants mais peu utilisés. Le souci avec les langages peu utilisés, c'est qu'il est
difficile de trouver des gens pour vous aider et vous conseiller quand vous avez un problème.
Voilà entre autres pourquoi le C++ est un bon choix pour qui veut débuter : il y a
suffisamment de gens qui développent en C++ pour que vous n'ayez pas à craindre de vous
retrouver tous seuls !
Bien entendu, il y a d'autres critères que la popularité. Le plus important à mes yeux est le
niveau du langage. Il existe des langages de haut niveau et d'autres de plus bas niveau.
Le C++ ? On considère qu'il fait partie de la seconde catégorie : c'est un langage dit « de bas
niveau ». Mais que cela ne vous fasse pas peur ! Même si programmer en C++ peut se révéler
assez complexe, vous aurez entre les mains un langage très puissant et particulièrement
rapide. En effet, si l'immense majorité des jeux sont développés en C++, c'est parce qu'il s'agit
du langage qui allie le mieux puissance et rapidité. Voilà ce qui en fait un langage
incontournable.
Langages de programmation
par "niveau"
Vous constaterez qu'il est en fait possible de programmer en binaire grâce à un langage très
basique appelé l'assembleur. Étant donné qu'il faut déployer des efforts surhumains pour
8
coder ne serait-ce qu'une calculatrice, on préfère le plus souvent utiliser un langage de
programmation.
En programmation, la notion de « niveau » est relative. Globalement, on peut dire que le C++
est « bas niveau » par rapport au Python, mais il est plus « haut niveau » que l'assembleur.
Tout dépend de quel point de vue on se place.
I.3.2. Résumé des forces du C++
• Il est très répandu. Comme nous l'avons vu, il fait partie des langages de
programmation les plus utilisés sur la planète. On trouve donc beaucoup de
documentation sur Internet et on peut facilement avoir de l'aide sur les forums. Il
paraît même qu'il y a des gens sympas qui écrivent des cours pour débutants
dessus.
• Il est rapide, très rapide même, ce qui en fait un langage de choix pour les
applications critiques qui ont besoin de performances. C'est en particulier le cas des
jeux vidéo, mais aussi des outils financiers ou de certains programmes militaires qui
doivent fonctionner en temps réel.
• Il est portable : un même code source peut théoriquement être transformé sans
problème en exécutable sous Windows, Mac OS et Linux. Vous n'aurez pas besoin de
réécrire votre programme pour d'autres plates-formes !
• Il existe de nombreuses bibliothèques pour le C++. Les bibliothèques sont des
extensions pour le langage, un peu comme des plug-ins. De base, le C++ ne sait pas
faire grand chose mais, en le combinant avec de bonnes bibliothèques, on peut créer
des programmes 3D, réseaux, audio, fenêtrés, etc.
• Il est multi-paradigmes . Ce mot barbare signifie qu'on peut programmer de
différentes façons en C++. Vous êtes encore un peu trop débutants pour que je vous
présente tout de suite ces techniques de programmation mais l'une des plus célèbres
est la Programmation Orientée Objet (POO). C'est une technique qui permet de
simplifier l'organisation du code dans nos programmes et de rendre facilement certains
morceaux de codes réutilisables. La partie II de ce cours sera entièrement dédiée à la
POO !
Bien entendu, le C++ n'est pas le langage incontournable. Il a lui-même ses défauts par
rapport à d'autres langages, sa complexité en particulier. Vous avez beaucoup de contrôle sur
le fonctionnement de votre ordinateur (et sur la gestion de la mémoire) : cela offre une grande
puissance mais, si vous l'utilisez mal, vous pouvez plus facilement faire planter votre
programme. Ne vous en faites pas, nous découvrirons tout cela progressivement dans ce
cours.
#include <iostream>
9
int main()
return 0;
La programmation a déjà une longue histoire derrière elle. Au début, il n'existait même pas de
clavier pour programmer ! On utilisait des cartes perforées pour donner des instructions à
l'ordinateur.
Les choses ont ensuite évolué, heureusement. Le clavier et les premiers langages de
programmation sont apparus :
10
des langages les plus utilisés aujourd'hui. %le plus utilisé, d'après langpop.com cité
plus haut !%
• 1983 : un peu plus tard, on a proposé d'ajouter des choses au langage C, de le faire
évoluer. Ce nouveau langage, que l'on a appelé « C++ », est entièrement basé sur le
C. Le langage C++ n'est en fait rien d'autre que le langage C avec plusieurs
nouveautés. Il s'agit de concepts de programmation poussés comme la programmation
orientée objet, le polymorphisme, les flux… Bref, des choses bien compliquées pour
nous pour le moment mais dont nous aurons l'occasion de reparler par la suite !
Une minute… Si le C++ est en fait une amélioration du C, pourquoi y a-t-il encore tant de
gens qui développent en C ?
Tout le monde n'a pas besoin des améliorations apportées par le langage C++. Le C est à lui
seul suffisamment puissant pour être à la base des systèmes d'exploitation comme Linux, Mac
OS X et Windows.
Ceux qui n'ont pas besoin des améliorations (mais aussi de la complexité !) apportées par le
langage C++ se contentent donc très bien du langage C et ce, malgré son âge. Comme quoi,
un langage peut être vieux et rester d'actualité.
I.4.2. Le concepteur
Bjarne Stroustrup est aujourd'hui professeur d'informatique à l'université Texas A&M, aux
Etats-Unis. Il s'agit d'une importante figure de l'univers informatique qu'il faut connaître, au
moins de nom (du moins si vous arrivez à le retenir !).
De nombreux langages de programmation se sont par la suite inspirés du C++. C'est
notamment le cas du langage Java.
Le langage C++, bien que relativement ancien, continue à être amélioré. Une nouvelle
version, appelée « C++1x », est d'ailleurs en cours de préparation. Il ne s'agit pas d'un
nouveau langage mais d'une mise à jour du C++. Les nouveautés qu'elle apporte sont
cependant trop complexes pour nous, nous n'en parlerons donc pas ici !
En résumé
11
II. Installez les logiciels nécessaires pour
programmer
Maintenant que l'on en sait un peu plus sur le C++, si on commençait à pratiquer pour entrer
dans le vif du sujet ?
Ah mais oui, c'est vrai : vous ne pouvez pas programmer tant que vous ne disposez pas des
bons logiciels ! En effet, il faut installer certains logiciels spécifiques pour programmer en
C++. Dans ce chapitre, nous allons les mettre en place et les découvrir ensemble.
Eh oui, il s'agit du compilateur, ce fameux programme qui permet de traduire votre langage
C++ en langage binaire !
Il en existe plusieurs pour le langage C++. Mais nous allons voir que le choix du compilateur
ne sera pas très compliqué dans notre cas.
12
• Soit on utilise un programme « 3-en-1 » (oui oui, comme les liquides vaisselle) qui
combine éditeur de texte, compilateur et débugger. Ces programmes « 3-en-1 » sont
appelés IDE (ou en français « EDI » pour « Environnement de Développement Intégré
»).
Il existe plusieurs environnements de développement. Au début, vous aurez peut-être un peu
de mal à choisir celui qui vous plaît. Une chose est sûre en tout cas: vous pouvez faire
n'importe quel type de programme, quel que soit l'IDE que vous choisissez.
Quand vous réalisez un programme, on dit que vous travaillez sur un projet. Un projet est
constitué de plusieurs fichiers de code source : des fichiers.cpp,.h, les images du programme,
etc.
Le rôle d'un IDE est de rassembler tous ces fichiers d'un projet au sein d'une même interface.
Ainsi, vous avez accès à tous les éléments de votre programme à portée de clic.
Voilà pourquoi, quand vous voudrez créer un nouveau programme, il faudra demander à l'IDE
de vous préparer un « nouveau projet ».
Il m'a semblé intéressant de vous montrer quelques IDE parmi les plus connus. Tous sont
disponibles gratuitement. Personnellement, je navigue un peu entre tous ceux-là et j'utilise
l'IDE qui me plaît selon l'humeur du jour.
• Le plus célèbre IDE sous Windows, c'est celui de Microsoft : Visual C++. Il existe à
la base en version payante (chère !) mais, heureusement, il en existe une version
gratuite intitulée Visual C++ Express qui est vraiment très bien (il y a peu de
différences avec la version payante). Il est très complet et possède un puissant module
de correction des erreurs (débuggage).
Fonctionne sous Windows uniquement.
• Un des IDE que je préfère s'appelle Code::Blocks. Il est gratuit et disponible pour la
plupart des systèmes d'exploitation. Je conseille d'utiliser celui-ci pour débuter (et
même pour la suite s'il vous plaît bien !).
Fonctionne sous Windows, Mac et Linux.
• Sur Mac OS X, vous pouvez aussi utiliser XCode, généralement fourni sur le CD
d'installation de Mac OS X. C'est un IDE très apprécié par tous ceux qui font de la
programmation sur Mac.Fonctionne sous Mac OS X uniquement.
Note pour les utilisateurs de Linux : il existe de nombreux IDE sous Linux, mais les
programmeurs expérimentés préfèrent parfois se passer d'IDE et compiler « à la main », ce
qui est un peu plus difficile. Vous aurez le temps d'apprendre à faire cela plus tard. En ce qui
nous concerne nous allons commencer par utiliser un IDE. Si vous êtes sous Linux, je vous
conseille d'installer Code::Blocks pour suivre mes explications.
Vous pouvez aussi jeter un coup d'œil du côté de l'Eclipse pour les développeurs C/C++,
très puissant et qui, contrairement à l'idée répandue, ne sert pas qu'à programmer en Java !
Quel est le meilleur de tous ces IDE ?
Tous ces IDE vous permettront de programmer et de suivre le reste de ce cours sans
problème. Certains sont plus complets au niveau des options, d'autres un peu plus intuitifs à
utiliser, mais dans tous les cas les programmes que vous créerez seront les mêmes quel que
soit l'IDE que vous utilisez. Ce choix n'est donc pas si crucial qu'on pourrait le croire.
13
Durant tout ce cours, j'utiliserai Visual C++. Si vous voulez avoir exactement les mêmes
écrans que moi, surtout au début pour ne pas être perdus, je vous recommande donc de
commencer par installer Visual C++.
14
Aperçu de Visual C++
Vous trouverez les instructions pour télécharger Visual C++ Express à cette adresse :
Sélectionnez Visual C++ Express Français un peu plus bas sur la page.
15
Visual C++ Express est en français et est totalement gratuit. Ce n'est donc pas une version
d'essai limitée dans le temps.
II.2.1 Installation
À la fin, on vous dit qu'il faut vous enregistrer dans les 30 jours. Pas de panique, c'est gratuit
et rapide mais il faut le faire.
Cliquez sur le lien qui vous est donné : vous arrivez sur le site de Microsoft. Connectez-vous
avec votre compte Windows Live ID (équivalent du compte Hotmail ou MSN) ou créez-en un
si vous n'en avez pas, puis répondez au petit questionnaire.
À la fin du processus, on vous donne à la fin une clé d'enregistrement. Vous devez recopier
cette clé dans le menu?>Inscrire le produit.
Pour créer un nouveau projet sous Visual, allez dans le menu Fichier>Nouveau>Projet.
SélectionnezWin32dans le panneau de gauche puis Application console Win32 à droite.
16
Ajout d'un projet
17
Assistant application
Cette fenêtre ne sert à rien. Par contre, cliquez sur Paramètres de l'application dans le panneau de
gauche.
18
Paramètres de l'application
Veillez à ce que l'option Projet vide soit cochée comme à la figure suivante.
Puis, cliquez sur Terminer.
Votre projet est pour l'instant bien vide. Faites un clic droit sur le dossier Fichiers sources situé
dans le panneau de gauche puis allez dan sAjouter>Nouvel élément.
19
Une fenêtre s'ouvre. SélectionnezFichier C++ (.cpp). Entrez le nom « main.cpp » pour votre
fichier.
Cliquez sur Ajouter. C'est bon, vous allez pouvoir commencer à écrire du code !
20
Fenêtre de Visual C++
1. La barre d'outils : tout ce qu'il y a de plus standard. Ouvrir, Enregistrer, Enregistrer tout,
Couper, Copier, Coller etc. Par défaut, il semble qu'il n'y ait pas de bouton de barre
d'outils pour compiler. Vous pouvez les rajouter en faisant un clic droit sur la barre
d'outils puis en choisissant Déboguer et Générer dans la liste.
Toutes ces icônes de compilation ont leur équivalent dans les menus Générer et
Déboguer. Si vous choisissez Générer, cela crée l'exécutable (cela signifie « Compiler »
pour Visual). Si vous sélectionnez Déboguer / Exécuter, on devrait vous proposer de
compiler avant d'exécuter le programme. La touche F7 permet de générer le projet
et F5 de l'exécuter.
2. La liste des fichiers du projet : dans cette zone très importante, vous voyez
normalement la liste des fichiers de votre projet. Cliquez sur l'onglet Explorateur de
21
solutions, en bas, si ce n'est déjà fait. Vous devriez voir que Visual crée déjà des
dossiers pour séparer les différents types de fichiers de votre projet (« sources », « en-
têtes » et « ressources »). Nous verrons un peu plus tard quels sont les différentes
sortes de fichiers qui constituent un projet.
3. La zone principale : c'est là qu'on modifie les fichiers source.
4. La zone de notification : c'est là encore la « zone de la mort », celle où l'on voit
apparaître toutes les erreurs de compilation. C'est également dans le bas de l'écran que
Visual affiche les informations de débuggage quand vous essayez de corriger un
programme buggé. Je vous ai d'ailleurs dit tout à l'heure que j'aimais beaucoup le
débugger de Visual et je pense que je ne suis pas le seul.
Voilà, on a fait le tour de Visual C++.
Vous pouvez aller jeter un œil dans les options (Outils>Options) si cela vous chante, mais n'y
passez pas 3 heures. Il faut dire qu'il y a tellement de cases à cocher partout qu'on ne sait plus
trop où donner de la tête.
En résumé
• Un IDE est un outil tout-en-un à destination des développeurs, qui permet de créer des
programmes.
• Un IDE est composé d'un éditeur de texte, d'un compilateur et d'un debugger.
• Code::Blocks, Visual C++ et Xcode sont parmi les IDE les plus connus pour
programmer en C++.
• Nous prendrons Code:: Blocks comme base dans la suite de ce cours.
22
III. Créez votre premier programme
Vous avez appris en quoi consiste la programmation et ce qu'est le C++, vous avez installé un
IDE (le logiciel qui va vous permettre de programmer) et maintenant vous vous demandez :
quand allons-nous commencer à coder ?
Alors bien sûr, ne vous mettez pas à imaginer que vous allez tout d'un coup faire des choses
folles. La 3D temps réel en réseau n'est pas vraiment au programme pour le moment ! À la
place, votre objectif dans ce chapitre est d'afficher un message à l'écran.
Quand je vous annonce que nous allons commencer à programmer, vous vous dites sûrement
« Chouette, je vais pouvoir faire ça, ça et ça ; et j'ai toujours rêvé de faire ça aussi ! ». Il est
de mon devoir de calmer un peu vos ardeurs et de vous expliquer comment cela va se passer.
Nous allons commencer doucement. Nous n'avons de toute façon pas le choix car les
programmes complexes 3D en réseau que vous imaginez peut-être nécessitent de connaître les
bases.
Il faut savoir qu'il existe 2 types de programmes : les programmes graphiques et les
programmes console.
Il s'agit des programmes qui affichent des fenêtres. Ce sont ceux que vous connaissez
sûrement le mieux. Ils génèrent à l'écran des fenêtres que l'on peut ouvrir, réduire, fermer,
agrandir…
Les programmeurs parlent de GUI (Graphical User Interface - Interface Utilisateur
Graphique).
23
Un programme GUI (graphique) : Word
Les programmes en console sont plus fréquents sous Linux que sous Windows et Mac OS X.
Ils sont constitués de simples textes qui s'affichent à l'écran, le plus souvent en blanc sur fond
noir.
24
Un programme en console
Bien entendu, je sais que vous ne voudrez pas en rester là. Rassurez-vous sur ce point : je
m'en voudrais de m'arrêter aux programmes console car je sais que beaucoup d'entre vous
préféreraient créer des programmes graphiques. Cela tombe bien : une partie toute entière de
ce cours sera dédiée à la création de GUI avec Qt, une sorte d'extension du C++ qui permet de
réaliser ce type de programmes !
Mais avant cela, il va falloir retrousser ses manches et se mettre au travail. Alors au boulot !
Au chapitre précédent, vous avez installé un IDE, ce fameux logiciel qui contient tout ce qu'il
faut pour programmer.
Nous avons découvert qu'il existait plusieurs IDE (Code::Blocks, Visual C++, Xcode…). Je
ne vous en ai cité que quelques-uns parmi les plus connus mais il y en a bien d'autres !
25
concurrents si nécessaire. Heureusement, ces logiciels se ressemblent beaucoup et emploient
le même vocabulaire, donc dans tous les cas vous ne serez pas perdus.
Pour commencer à programmer, la première étape consiste à demander à son IDE de créer un
nouveau projet. C'est un peu comme si vous demandiez à Word de vous créer un nouveau
document.
Nouveau projet
Code::Blocks
À la fin des étapes de l'assistant, le projet est créé et contient un premier fichier. Déployez
l'arborescence à gauche pour voir apparaître le fichier main.cpp et faites un double-clic dessus
pour l'ouvrir. Ce fichier est notre premier code source et il est déjà un peu rempli !
26
Premier programme dans Code::Blocks
Code::Blocks vous a créé un premier programme très simple qui affiche à l'écran le message «
Hello world! » (cela signifie quelque chose comme « Bonjour tout le monde ! »).
Il y a déjà une dizaine de lignes de code source C++ et je n'y comprends rien !
Oui, cela peut paraître un peu difficile la première fois mais nous allons voir ensemble, un peu
plus loin, ce que signifie ce code.
Pour le moment, j'aimerais que vous fassiez une chose simple : essayez de compiler et de
lancer ce premier programme. Vous vous souvenez comment faire ? Il y a un bouton «
Compiler et exécuter » (Build and run). Ce bouton se trouve dans la barre d'outils (figure
suivante).
27
Les boutons de compilation
La compilation se lance alors. Vous allez voir quelques messages s'afficher en bas de l'IDE
(dans la section Build log).
Si la compilation ne fonctionne pas et que vous avez une erreur de ce type : «"My-program -
Release" uses an invalid compiler. Skipping… Nothing to be done. », cela signifie que vous avez
téléchargé la version de Code::Blocks sans mingw (le compilateur). Retournez sur le site de
Code::Blocks pour télécharger la version avec mingw.
Si tout va bien, une console apparaît avec notre programme (figure suivante).
Vous voyez que le programme affiche bel et bien « Hello world! » dans la console !
N'est-ce pas beau !? Vous venez de compiler votre tout premier programme !
Un fichier exécutable a été généré sur votre disque dur. Sous Windows, c'est un fichier.exe.
Vous pouvez le retrouver dans un sous-dossier release(ou parfois debug), situé dans le dossier
bin de votre projet.
Au fait, que signifie le message à la fin de la console : «Process returned 0 (0x0) execution time :
0.004 s Press any key to continue.» ?
Ah, bonne question !
Ce message n'a pas été écrit par votre programme mais par votre IDE. En l’occurrence, c'est
Code::Blocks qui affiche un message pour signaler que le programme s'est bien déroulé et le
temps qu'a duré son exécution.
Le but de Code::Blocks est ici surtout de « maintenir » la console ouverte. En effet, sous
Windows en particulier, dès qu'un programme console est terminé, la fenêtre de la console se
ferme. Or, le programme s'étant exécuté ici en 0.004s, vous n'auriez pas eu le temps de voir le
message s'afficher à l'écran !
28
Code::Blocks vous invite donc à « appuyer sur n'importe quelle touche pour continuer », ce
qui aura pour effet de fermer la console.
Lorsque vous compilez et exécutez un programme « console » comme celui-ci avec Visual
C++, la console a tendance à s'ouvrir et se refermer instantanément. Visual C++ ne maintient
pas la console ouverte comme Code::Blocks.
Si vous utilisez Visual C++, la solution consiste à ajouter la ligne system("PAUSE");avant la
lignereturn 0;de votre programme.
Lorsque Code::Blocks crée un nouveau projet, il génère un fichier main.cpp contenant ce code :
#include <iostream>
int main()
return 0;
}
Tous les IDE proposent en général de démarrer avec un code similaire. Cela permet de
commencer à programmer plus vite.
Vous retrouverez les 3 premières lignes (include,using namespace et int main) dans quasiment tous
vos programmes C++. Vous pouvez considérer que tous vos programmes commenceront par
ces lignes.
Sans trop entrer dans les détails (car cela pourrait devenir compliqué pour un début !), je vais
vous présenter à quoi sert chacune de ces lignes.
include
#include <iostream>
C'est ce qu'on appelle une directive de préprocesseur. Son rôle est de « charger » des
fonctionnalités du C++ pour que nous puissions effectuer certaines actions.
En effet, le C++ est un langage très modulaire. De base, il ne sait pas faire grand-chose (pas
même afficher un message à l'écran !). On doit donc charger des extensions que l'on
appelle bibliothèques et qui nous offrent de nouvelles possibilités.
29
Ici, on charge le fichier iostream, ce qui nous permet d'utiliser une bibliothèque… d'affichage
de messages à l'écran dans une console ! Quelque chose de vraiment très basique, comme
vous le voyez, mais qui nécessite quand même l'utilisation d'une bibliothèque.
Appeler iostream nous permet en fait de faire un peu plus qu'afficher des messages à l'écran :
on pourra aussi récupérer ce que saisit l'utilisateur au clavier, comme nous le verrons plus
tard.
iostream signifie « Input Output Stream », ce qui veut dire « Flux d'entrée-sortie ». Dans un
ordinateur, l'entrée correspond en général au clavier ou à la souris, et la sortie à l'écran.
Inclure iostream nous permet donc en quelque sorte d'obtenir tout ce qu'il faut pour échanger
des informations avec l'utilisateur.
Plus tard, nous découvrirons de nouvelles bibliothèques et il faudra effectuer des inclusions en
haut des codes source comme ici. Par exemple, lorsque nous étudierons Qt, qui permet de
réaliser des programmes graphiques (GUI), on insérera une ligne comme celle-ci :
#include <Qt>
Notez qu'on peut charger autant de bibliothèques que l'on veut à la fois.
using namespace
La ligne :
Pour éviter ce genre de problèmes, on a créé des namespaces (espaces de noms), qui sont des
sortes de dossiers à noms. La ligne using namespace std; indique que vous allez utiliser l'espace
de noms std dans la suite de votre fichier de code. Cet espace de noms est un des plus connus
car il correspond à la bibliothèque standard (std), une bibliothèque livrée par défaut avec le
langage C++ et dont iostream fait partie.
int main()
C'est ici que commence vraiment le cœur du programme. Les programmes, vous le verrez,
sont essentiellement constitués de fonctions. Chaque fonction a un rôle et peut appeler
d'autres fonctions pour effectuer certaines actions.
Tous les programmes possèdent une fonction dénommée « main » (Qui se prononce « mèïne »
en anglais), ce qui signifie « principale ». C'est donc la fonction principale.
int main()
30
}
Les accolades déterminent le début et la fin de la fonction. Comme vous le voyez dans le code
source qui a été généré par Code::Blocks, il n'y a rien après la fonction main. C'est normal : à
la fin de la fonction main le programme s'arrête ! Tout programme commence au début de la
fonction main et se termine à la fin de celle-ci.
Cela veut dire qu'on va écrire tout notre programme dans la fonctionmain?
Non ! Bien que ce soit possible, ce serait très délicat à gérer, surtout pour de gros
programmes. À la place, la fonction main appelle d'autres fonctions qui, à leur tour, appellent
d'autres fonctions. Bref, elle délègue le travail.
Cependant, dans un premier temps, nous allons surtout travailler dans la fonction main car nos
programmes resteront assez simples.
cout
Voici enfin la première ligne qui fait quelque chose de concret ! C'est la première ligne de
main, donc la première action qui sera exécutée par l'ordinateur (les lignes que nous avons
vues précédemment ne sont en fait que des préparatifs pour le programme).
Notez que cout est fourni par iostream. Si vous n'incluez pas iostream au début de votre
programme, le compilateur se plaindra de ne pas connaître cout et vous ne pourrez pas générer
votre programme !
Notez bien : chaque instruction se termine par un point-virgule ! C'est d'ailleurs ce qui vous
permet de différencier les instructions du reste.
Si vous oubliez le point-virgule, la compilation ne fonctionnera pas et votre programme ne
pourra pas être créé !
Il y a 3 éléments sur cette ligne :
cout << "Bonjour tout le monde !" << endl << "Comment allez-vous ?" << endl;
… affiche ces deux phrases sur deux lignes différentes. Essayez ce code, vous verrez !
Sous Windows, les caractères accentués s'affichent mal (essayez d'afficher « Bonjour Gérard
» pour voir !). C'est un problème de la console de Windows (problème qu'on peut retrouver
plus rarement sous Mac OS X et Linux). Il existe des moyens de le régler mais aucun n'est
vraiment satisfaisant. À la place, je vous recommande plutôt d'éviter les accents dans les
programmes console sous Windows.
Rassurez-vous : les GUI que nous créerons plus tard avec Qt n'auront pas ce problème !
31
Pour être sûr de bien comprendre ce qui se passe, je vous invite à créer vos propres exemples
et à afficher ce qui vous passe par la tête. N'oubliez pas d’utiliser endl pour réaliser des retours
à la ligne et de séparer chaque morceau de texte par les chevrons<<. D'ailleurs, vous devriez
être fier de ces essais, ce sont les premiers programmes C++ que vous réalisez tout seul sans
copier depuis un cours ! Je vous conseille de faire de même tout au long de ce cours. A
chaque que fois qu'il y aura des exemples, essayez de modifier les instructions, de voir ce qui
se passe si on change l'ordre, bref de "bidouiller", c'est le meilleur moyen d'apprendre.
Au cours de vos essais, vous avez peut-être essayé d'afficher un back slash (\) ou des
guillemets ("). Si ce n'est pas le cas, je vous propose de le faire maintenant:
#include <iostream>
int main()
cout << "Je fais des tests pour apprendre le C++ !" << endl;
return 0;
}
Le compilateur ne va pas aimer cela du tout et il un message d'erreur devrait s'afficher dans la
zone au bas de votre fenêtre Code::Blocks. La raison est simple, pour afficher des guillemets,
il faut utiliser la combinaison\"et pas juste", idem pour le backslash qu'il faut doubler. Il faut
donc écrire:
#include <iostream>
int main()
cout << "Je fais des tests pour apprendre le C++ !" << endl;
32
cout << "\\" << endl;
return 0;
}
Je vous laisse faire le test pour vérifier que cela fonctionne. Maintenant que vous avez vu ces
deux petites exceptions, vous êtes prêt à écrire tout ce qui vous passera par la tête dans la
console. Voyons maintenant ce qui se passe à la fin de notre programme.
return
return 0;
Ce type d'instruction clôt généralement les fonctions. En fait, la plupart des fonctions
renvoient une valeur (un nombre par exemple). Ici, la fonction main renvoie 0 pour indiquer
que tout s'est bien passé (toute valeur différente de 0 aurait indiqué un problème).
Vous n'avez pas besoin de modifier cette ligne, laissez-la telle quelle. Nous aurons d'autres
occasions d'utiliser return pour d'autres fonctions, nous en reparlerons !
En plus du code qui donne des instructions à l'ordinateur, vous pouvez écrire des
commentaires pour expliquer le fonctionnement de votre programme.
Les commentaires n'ont aucun impact sur le fonctionnement de votre logiciel : en fait, le
compilateur ne les lit même pas et ils n'apparaissent pas dans le programme généré. Pourtant,
ces commentaires sont indispensables pour les développeurs : ils leur permettent d'expliquer
ce qu'ils font dans leur code !
Dès que vos programmes vont devenir un petit peu complexes (et croyez-moi, cela ne tardera
pas), vous risquez d'avoir du mal à vous souvenir de leur fonctionnement quelque temps après
avoir écrit le code source. De plus, si vous envoyez votre code à un ami, il aura des difficultés
pour comprendre ce que vous avez essayé de faire juste en lisant le code source. C'est là que
les commentaires entrent en jeu !
Il y a deux façons d'écrire des commentaires selon leur longueur. Je vais vous les présenter
toutes les deux.
33
cout << "Hello world!" << endl; // Affiche un message à l'écran
Les commentaires longs
Si votre commentaire tient sur plusieurs lignes, ouvrez la zone de commentaire avec/*et
fermez-la avec*/:
/*
*/
int main()
}
Si vous lancez ce programme, vous ne verrez aucune nouveauté. Les commentaires sont,
comme je vous le disais, purement ignorés par le compilateur.
34
J'ai volontairement commenté chaque ligne de code ici mais, dans la pratique il ne faut pas
non plus commenter à tout-va. Si une ligne de code fait quelque chose de vraiment évident,
inutile de la commenter.
En fait, les commentaires sont plus utiles pour expliquer le fonctionnement d'une série
d'instructions plutôt que chaque instruction une à une.
Un autre élément important pour les développeurs est la mise en forme du code. Le
compilateur ne s'intéresse pas aux espaces ou aux retours à la ligne présents dans le code
source. En fait, ils ne sont là que pour nous aider, nous les humains, à lire le code. Le
compilateur serait tout à fait heureux de compiler ce code:
#include <iostream>
Pour nous aider dans cette tâche, Code::Blocks met à disposition un outil. Ouvrez le
menu Pluginspuis sélectionnez Source code formatter (AStyle). Votre code source se met
alors en forme tout seul et devient automatiquement plus lisible ! Cela n'a rien changé pour le
compilateur, le programme fera toujours exactement la même chose, par contre, pour vous (et
vos collègues travaillant sur le même projet), cela change tout. Vous verrez que plus on
avance dans ce cours, plus cela deviendra important d'avoir un code mis en forme proprement
et bien commenté.
En résumé
• On distingue deux types de programmes : les programmes graphiques (GUI) et les
programmes console.
• Il est plus simple de réaliser des programmes console pour commencer, c'est donc ce
type de programme que nous étudierons en premier.
• Un programme possède toujours une fonction main(): c'est son point de démarrage.
• La directive coutpermet d'afficher du texte dans une console.
• On peut ajouter des commentaires dans son code source pour expliquer son
fonctionnement. Ils prennent la forme// Commentaireou /* Commentaire */.
35
VII. Définissez les variables pour utiliser la mémoire
Jusqu'à présent, vous avez découvert comment créer et compiler vos premiers programmes en
mode console. Pour l'instant ces programmes sont très simples. Ils affichent des messages à
l'écran… et c'est à peu près tout.
Cela est principalement dû au fait que vos programmes ne savent pas interagir avec leurs
utilisateurs. C'est ce que nous allons apprendre à faire dans le chapitre suivant.
Mais avant cela, il va nous falloir travailler dur puisque je vais vous présenter une notion
fondamentale en informatique. Nous allons parler des variables.
Les variables permettent d'utiliser la mémoire de l'ordinateur afin de stocker une information
pour pouvoir la réutiliser plus tard. J'imagine que vous avez tous déjà eu une calculatrice entre
les mains. Sur ces outils, il y a généralement des touches M+ , M- , MC , etc. qui permettent de
stocker dans la mémoire de la calculatrice le résultat intermédiaire d'un calcul et de reprendre
ce nombre plus tard.
Nous allons apprendre à faire la même chose avec votre ordinateur qui n'est, après tout,
qu'une grosse machine à calculer.
Je vous rassure tout de suite, nous n'avons absolument pas besoin de comprendre comment
cela marche pour pouvoir, nous aussi, mettre des valeurs dans la mémoire de l'ordinateur.
Toute la partie compliquée sera gérée par le compilateur et le système d'exploitation. Elle
n'est pas belle la vie ?
La seule et unique chose que vous ayez besoin de savoir, c'est qu'une variable est une partie
de la mémoire que l'ordinateur nous prête pour y mettre des valeurs. Imaginez que l'ordinateur
possède dans ses entrailles une grande armoire. Cette dernière possède des milliers (des
milliards !) de petits tiroirs ; ce sont des endroits que nous allons pouvoir utiliser pour mettre
nos variables.
36
Dans le cas d'une calculatrice toute simple, on ne peut généralement stocker qu'un seul
nombre à la fois. Vous vous doutez bien que, dans le cas d'un programme, il va falloir
conserver plus d'une chose simultanément. Il faut donc un moyen de différencier les variables
pour pouvoir y accéder par la suite. Chaque variable possède donc un nom. C'est en quelque
sorte l'étiquette qui est collée sur le tiroir.
L'autre chose qui distingue la calculatrice de l'ordinateur, c'est que nous aimerions pouvoir
stocker des tas de choses différentes, des nombres, des lettres, des phrases, des images, etc.
C'est ce qu'on appelle le type d'une variable. Vous pouvez vous imaginer cela comme étant la
forme du tiroir. En effet, on n'utilise pas les mêmes tiroirs pour stocker des bouteilles ou des
livres.
À cela s'ajoute une règle supplémentaire, valable pour tout ce que l'on écrit en C++ et pas
seulement pour les variables. Le langage fait la différence entre les majuscules et les
minuscules. En termes techniques, on dit que C++ est sensible à la casse. Donc, nomZero,
nomzero, NOMZERO et NomZeRo sont tous des noms de variables différents.
Pour des questions de lisibilité, il est important d'utiliser des noms de variables qui décrivent
bien ce qu'elles contiennent. On préfèrera donc choisir comme nom de variable ageUtilisateur
plutôt que maVar ou variable1.
Pour le compilateur, cela ne fait aucune différence. Mais, pour vous et pour les gens qui
travailleront avec vous sur le même programme, c'est très important.
Personnellement, j'utilise une « convention » partagée par beaucoup de programmeurs. Dans
tous les gros projets regroupant des milliers de programmeurs, on trouve des règles très
strictes et parfois difficiles à suivre. Celles que je vous propose ici permettent de garder une
bonne lisibilité et surtout, elles vous permettront de bien comprendre tous les exemples dans
la suite de ce cours.
37
• maVar:
non, car le nom ne décrit pas ce que contient la variable ;
• ageUtilisateur: ok.
Je vous conseille fortement d'adopter la même convention. Rendre son code lisible et
facilement compréhensible par d'autres programmeurs est très important, et cela ne passe pas
que par la mise en forme.
Une erreur courante est d'avoir deux variables avec le même nom dans la même fonction.
Cela ne peut pas marcher puisque le compilateur ne pourra pas savoir quel tiroir de sa
mémoire vous désirez utiliser. Il faut donc choisir des noms de variable unique à l'intérieur
d'une même fonction.
Reprenons. Nous avons appris qu'une variable a un nom et un type. Nous savons comment
nommer nos variables, voyons maintenant leurs différents types. L'ordinateur aime savoir ce
qu'il a dans sa mémoire, il faut donc indiquer quel type d'élément va contenir la variable que
nous aimerions utiliser. Est-ce un nombre, un mot, une lettre ? Il faut le spécifier.
Voici donc la liste des types de variables que l'on peut utiliser en C++ :
bool Une valeur parmi deux possibles, vrai (true) ou faux (false).
char Un caractère.
Ces types ont des limites de validité, des bornes, c'est-à-dire qu'il y a des nombres qui sont
trop grands pour un int par exemple. Ces bornes dépendent de votre ordinateur, de votre
système d'exploitation et de votre compilateur. Sachez simplement que ces limites sont bien
assez grandes pour la plupart des utilisations courantes.
Cela ne devrait donc pas vous poser de problème, à moins que vous ne vouliez créer des
programmes pour téléphones portables ou pour des micro-contrôleurs, qui ont parfois des
bornes plus basses que les ordinateurs.
Il existe également d'autres types avec d'autres limites mais ils sont utilisés plus rarement.
Quand on a besoin d'une variable, il faut donc se poser la question du genre de choses qu'elle
va contenir. Si vous avez besoin d'une variable pour stocker le nombre de personnes qui
utilisent votre programme, alors utilisez un int ou unsigned int, ; pour stocker le poids d'un
38
gigot, on utilisera un double et pour conserver en mémoire le nom de votre meilleur ami, on
choisira une chaîne de caractères string.
Assez parlé, il est temps d'entrer dans le vif du sujet et de demander à l'ordinateur de nous
prêter un de ses tiroirs. En termes techniques, on parle de déclaration de variable.
Il nous faut indiquer à l'ordinateur le type de la variable que nous voulons, son nom et enfin sa
valeur. Pour ce faire, c'est très simple : on indique les choses exactement dans l'ordre présenté
à la figure suivante.
On peut aussi utiliser la même syntaxe que dans le langage C (figure suivante).
Les deux versions sont strictement équivalentes. Je vous conseille cependant d'utiliser la
première pour des raisons qui deviendront claires plus tard. La deuxième version ne sera pas
utilisée dans la suite du cours, je vous l'ai présentée ici pour que vous puissiez comprendre les
nombreux exemples que l'on peut trouver sur le web et qui utilisent cette version de la
déclaration d'une variable.
N'oubliez pas le point-virgule (;) à la fin de la ligne ! C'est le genre de choses que l'on oublie
très facilement et le compilateur n'aime pas cela du tout.
Reprenons le morceau de code minimal et ajoutons-y une variable pour stocker l'âge de
l'utilisateur.
#include <iostream>
int main()
39
int ageUtilisateur(16);
return 0;
}
Que se passe-t-il à la ligne 6 de ce programme ?
L'ordinateur voit que l'on aimerait lui emprunter un tiroir dans sa mémoire avec les propriétés
suivantes :
Comme nous allons avoir besoin de beaucoup de tiroirs dans la suite du cours, je vous
propose d'utiliser des schémas un peu plus simples. On va beaucoup les utiliser par la suite, il
est donc bien de s'y habituer tôt.
40
Schéma de
l'état de la mémoire après la déclaration d'une variable
Je vais vous décrire ce qu'on voit sur le schéma. Le gros rectangle bleu représente la mémoire
de l'ordinateur. Pour l'instant, elle est presque vide. Le carré jaune est la zone de mémoire que
l'ordinateur nous a prêtée. C'est l'équivalent de notre tiroir. Il contient, comme avant, le
nombre 16 et on peut lire le nom ageUtilisateur sur l'étiquette qui y est accrochée.
Je ne suis pas bon en dessin, donc il faut un peu d'imagination, mais le principe est là.
#include <iostream>
int main()
int ageUtilisateur(16);
41
double pi(3.14159);
char lettre('a');
return 0;
}
Il y a deux choses importantes à remarquer ici. La première est que les variables de type bool
ne peuvent avoir pour valeur que true ou false, c'est donc une de ces deux valeurs qu'il faut
mettre entre les parenthèses. Le deuxième point à souligner, c'est que, pour le type char, il faut
mettre la lettre souhaitée entre apostrophes. Il faut écrire char lettre('a');et pas char lettre(a);. C'est
une erreur que tout le monde fait, moi le premier.
Il est toujours bien de mettre un commentaire pour expliquer à quoi va servir la variable.
Je peux donc compléter mon schéma en lui ajoutant nos nouvelles variables (figure suivante).
42
Vous pouvez évidemment compiler et tester le programme ci-dessus. Vous constaterez qu'il
ne fait strictement rien. J'espère que vous n'êtes pas trop déçus. Il se passe en réalité
énormément de choses mais, comme je vous l'ai dit au début, ces opérations sont cachées et
ne nous intéressent pas vraiment. En voici quand même un résumé chronologique.
Les chaînes de caractères sont un petit peu plus complexe à déclarer mais rien
d'insurmontable, je vous rassure. La première chose à faire est d'ajouter une petite ligne au
début de votre programme. Il faut, en effet, indiquer au compilateur que nous souhaitons
utiliser des strings. Sans cela, il n'inclurait pas les outils nécessaires à leur gestion. La ligne à
ajouter est #include <string>.
#include <iostream>
#include <string>
int main()
return 0;
}
L'autre différence se situe au niveau de la déclaration elle-même. Comme vous l'avez
certainement constaté, j'ai placé des guillemets autour de la valeur. Un peu comme pour
lescharmais, cette fois, ce sont des guillemets doubles (") et pas juste des apostrophes (').
D'ailleurs votre IDE devrait colorier les mots"Albert Einstein"d'une couleur différente du'a'de
l'exemple précédent. Confondre'et"est une erreur, là encore, très courante qui fera hurler de
douleur votre compilateur. Mais ne vous en faites pas pour lui, il en a vu d'autres.
43
VII.4.2. Une astuce pour gagner de la place
Avant de passer à la suite, il faut que je vous présente une petite astuce utilisée par certains
programmeurs.
Si vous avez plusieurs variables du même type à déclarer, vous pouvez le faire sur une seule
ligne en les séparant par une virgule (,). Voici comment :
int a(2),b(4),c(-1); //On déclare trois cases mémoires nommées a, b et c et qui contiennent respectivement les valeurs 2, 4 et
-1
string prenom("Albert"), nom("Einstein"); //On déclare deux cases pouvant contenir des chaînes de caractères
Ça peut être pratique quand on a besoin de beaucoup de variables d'un coup. On économise la
répétition du type à chaque variable. Mais je vous déconseille quand même de trop abuser de
cette astuce : le programme devient moins lisible et moins compréhensible.
Maintenant que nous avons vu le principe général, il est temps de plonger un petit peu plus
dans les détails.
Lors de la déclaration d'une variable, votre programme effectue en réalité deux opérations
successives.
Il arrive parfois que l'on ne sache pas quelle valeur donner à une variable lors de sa
déclaration. Il est alors possible d'effectuer uniquement l'allocation sans l'initialisation.
Il suffit d'indiquer le type et le nom de la variable sans spécifier de valeur (figure suivante).
#include <iostream>
#include <string>
int main()
44
{
string nomJoueur;
int nombreJoueurs;
return 0;
}
Une erreur courante est de mettre des parenthèses vides après le nom de la variable, comme
ceci :int nombreJoueurs(). C'est incorrect, il ne faut pas mettre de parenthèses, juste le type et le
nom.
Simple non ? Je savais que cela allait vous plaire. Et je vous offre même un schéma en bonus
!
On a bien trois cases dans la mémoire et les trois étiquettes correspondantes. La chose
nouvelle est que l'on ne sait pas ce que contiennent ces trois cases. Nous verrons dans le
45
chapitre suivant comment modifier le contenu d'une variable et donc remplacer ces points
d'interrogation par d'autres valeurs plus intéressantes.
Je viens de vous montrer comment déclarer des variables sans leur donner de valeur initiale.
Je vous conseille par contre de toujours initialiser vos variables. Ce que je vous ai montré là
n'est à utiliser que dans les cas où l'on ne sait vraiment pas quoi mettre comme valeur, ce qui
est très rare.
Il est temps d'apprendre à effectuer quelques opérations avec nos variables parce que vous en
conviendrez, pour l'instant, on n'a pas appris grand chose d'utile. Notre écran est resté
désespérément vide.
Au chapitre précédent, vous avez appris à afficher du texte à l'écran. J'espère que vous vous
souvenez encore de ce qu'il faut faire.
Oui, c'est bien cela. Il faut utilisercoutet les chevrons (<<). Parfait. En effet, pour afficher le
contenu d'une variable, c'est la même chose. À la place du texte à afficher, on met simplement
le nom de la variable.
#include <iostream>
int main()
int ageUtilisateur(16);
return 0;
}
Une fois compilé, ce code affiche ceci à l'écran :
Votre age est : 16
Exactement ce que l'on voulait ! On peut même faire encore plus simple : tout mettre sur une
seule ligne ! Et on peut même ajouter un retour à la ligne à la fin.
46
Pensez à mettre un espace à la fin du texte. Ainsi, la valeur de votre variable sera détachée du
texte lors de l'affichage.
#include <iostream>
int main()
int ageUtilisateur(16);
cout << "Votre age est : " << ageUtilisateur << endl;
return 0;
}
Et on peut même afficher le contenu de plusieurs variables à la fois.
#include <iostream>
#include <string>
int main()
int qiUtilisateur(150);
cout << "Vous vous appelez " << nomUtilisateur << " et votre QI vaut " << qiUtilisateur << endl;
return 0;
}
Ce qui affiche le résultat escompté.
Vous vous appelez Albert Einstein et votre QI vaut 150
47
Mais je pense que vous n'en doutiez pas vraiment. Nous verrons au prochain chapitre
comment faire le contraire, c'est-à-dire récupérer la saisie d'un utilisateur et la stocker dans
une variable.
Les références
Avant de terminer ce chapitre, il nous reste une notion importante à voir. Il s'agit
des références. Je vous ai expliqué au tout début de ce chapitre qu'une variable pouvait être
considérée comme une case mémoire avec une étiquette portant son nom. Dans la vraie vie,
on peut très bien mettre plusieurs étiquettes sur un objet donné. En C++, c'est la même chose,
on peut coller une deuxième (troisième, dixième, etc.) étiquette à une case mémoire.
On obtient alors un deuxième moyen d'accéder à la même case mémoire. Un petit peu comme
si on donnait un surnom à une variable en plus de son nom normal. On parle parfois d'alias,
mais le mot correct en C++ est référence.
On a une seule case mémoire mais deux étiquettes qui lui sont accrochées.
Au niveau du code, on utilise une esperluette (&) pour déclarer une référence sur une
variable. Voyons cela avec un petit exemple.
int& maVariable(ageUtilisateur); //Déclaration d'une référence nommée maVariable qui est accrochée à la variable
ageUtilisateur
48
À la ligne 1, on déclare une case mémoire nomméeageUtilisateurdans laquelle on met le nombre
16. Et à la ligne 3, on accroche une deuxième étiquette à cette case mémoire. On a donc
dorénavant deux moyens d'accéder au même espace dans la mémoire de notre ordinateur.
La référence doit impérativement être du même type que la variable à laquelle elle est
accrochée ! Unint&ne peut faire référence qu'à unint, de même qu'unstring&ne peut être associé
qu'à une variable de typestring.
Essayons pour voir. On peut afficher l'âge de l'utilisateur comme d'habitude et via une
référence.
#include <iostream>
int main()
cout << "Vous avez " << ageUtilisateur << " ans. (via variable)" << endl;
cout << "Vous avez " << maReference << " ans. (via reference)" << endl;
49
return 0;
}
Ce qui donne évidemment le résultat escompté.
Vous avez 18 ans. (via variable)
Vous avez 18 ans. (via reference)
Une fois qu'elle a été déclarée, on peut manipuler la référence comme si on manipulait la
variable elle-même. Il n'y a aucune différence entre les deux.
En résumé
• Une variable est une information stockée en mémoire.
• Il existe différents types de variables en fonction de la nature de l'information à
stocker :int,char,bool…
• Une variable doit être déclarée avant utilisation. Exemple :int ageUtilisateur(16);
• La valeur d'une variable peut être affichée à tout moment aveccout.
• Les références sont des étiquettes qui permettent d'appeler une variable par un autre
nom. Exemple :int& maReference(ageUtilisateur);
50
IV. Implémentez les opérations d'une calculatrice
J'ai commencé à vous parler de variables au chapitre précédent en vous présentant la mémoire
d'une calculatrice. Un ordinateur étant une super-super-super-calculatrice, on doit pouvoir lui
faire faire des calculs et pas uniquement sauvegarder des données. J'espère que cela vous
intéresse, parce que c'est ce que je vais vous apprendre à faire.
Nous allons commencer en douceur avec la première tâche qu'on effectue sur une calculette.
Vous voyez de quoi je veux parler ? Oui c'est cela, écrire des nombres pour les mettre dans la
machine. Nous allons donc voir comment demander des informations à l'utilisateur et
comment les stocker dans la mémoire. Nous aurons donc besoin de… variables !
Dans un deuxième temps, je vais vous présenter comment effectuer de petits calculs.
Finalement, comme vous savez déjà comment afficher un résultat, vous pourrez mettre tout
votre savoir en action avec un petit exercice.
Au chapitre précédent, je vous ai expliqué comment afficher des variables dans la console.
Voyons maintenant comment faire le contraire, c'est-à-dire demander des informations à
l'utilisateur pour les stocker dans la mémoire.
Ce n'est pas tout ! Associés àcout, il y avait les chevrons (<<). Dans le cas decin, il y en a aussi,
mais dans l'autre sens (>>).
#include <iostream>
int main()
51
int ageUtilisateur(0); //On prepare une case mémoire pour stocker un entier
cin >> ageUtilisateur; //On fait entrer un nombre dans cette case
cout << "Vous avez " << ageUtilisateur << " ans !" << endl; //Et on l'affiche
return 0;
}
Je vous invite à tester ce programme. Voici ce que cela donne avec mon âge :
Quel age avez-vous ?
23
Vous avez 23 ans !
Que s'est-il passé exactement ?
Le programme a affiché le texteQuel age avez-vous ?. Jusque-là, rien de bien sorcier. Puis,
comme on l'a vu précédemment, à la ligne 8, le programme demande à l'ordinateur une case
mémoire pour stocker unintet il baptise cette caseageUtilisateur.
Ensuite, cela devient vraiment intéressant. L'ordinateur affiche un curseur blanc clignotant et
attend que l'utilisateur écrive quelque chose. Quand celui-ci a terminé et appuyé sur la
touche Entrée de son clavier, le programme prend ce qui a été écrit et le place dans la case
mémoireageUtilisateur à la place du 0 qui s'y trouvait.
Finalement, on retombe sur quelque chose de connu, puisque le programme affiche une petite
phrase et le contenu de la variable.
• Une astuce pour les chevrons
Il arrive souvent que l'on se trompe dans le sens des chevrons. Vous ne seriez pas les premiers
à écrirecout >>oucin <<, ce qui est faux.
Pour se souvenir du sens correct, je vous conseille de considérer les chevrons comme si
c'étaient des flèches indiquant la direction dans laquelle les données se déplacent. Depuis la
variable verscoutou depuiscinvers votre variable.
52
Schéma mnémotechnique indiquant le sens des chevrons à utiliser
Quand on affiche la valeur d'une variable, les données sortent du programme, on utilise donc
une flèche allant de la variable verscout. Quand on demande une information à l'utilisateur,
c'est le contraire, la valeur vient decinet va dans la variable.
Évidemment, ce que je vous ai présenté marche aussi avec d'autres types de variables. Voyons
cela avec un petit exemple.
#include <iostream>
#include <string>
int main()
string nomUtilisateur("Sans nom"); //On crée une case mémoire pour contenirune chaine de caractères
cin >> nomUtilisateur; //On remplit cette case avec ce qu'écrit l'utilisateur
53
cout << "Combien vaut pi ?" << endl;
double piUtilisateur(-1.); //On crée une case mémoire pour stocker un nombre réel
cout << "Vous vous appelez " << nomUtilisateur << " et vous pensez que pivaut " << piUtilisateur << "." << endl;
return 0;
}
Je crois que je n'ai même pas besoin de donner d'explications. Je vous invite néanmoins à
tester pour bien comprendre en détail ce qui se passe.
Avez-vous testé le code précédent en mettant vos nom et prénom ? Regardons ce que cela
donne.
Quel est votre prenom ?
Albert Einstein
Combien vaut pi ?
Vous vous appelez Albert et vous pensez que pi vaut 0.
L'ordinateur n'a rien demandé pour pi et le nom de famille a disparu ! Que s'est-il passé ?
C'est un problème d'espaces. Quand on appuie sur la touche Entrée , l'ordinateur copie ce qui a
été écrit par l'utilisateur dans la case mémoire. Mais il s'arrête au premier espace ou retour à
la ligne. Quand il s'agit d'un nombre, cela ne pose pas de problème puisqu'il n'y a pas d'espace
dans les nombres.
Pour les string, la question se pose. Il peut très bien y avoir un espace dans une chaîne de
caractères. Et donc l'ordinateur va couper au mauvais endroit, c'est-à-dire après le premier
mot. Et comme il n'est pas très malin, il va croire que le nom de famille correspond à la valeur
de pi !
En fait, il faudrait pouvoir récupérer toute la ligne plutôt que seulement le premier mot. Et si
je vous le propose, c'est qu'il y a une solution pour le faire !
Il faut utiliser la fonction getline(). Nous verrons plus loin ce que sont exactement les fonctions
mais, pour l'instant, voyons comment faire dans ce cas particulier.
#include <iostream>
#include <string>
54
int main()
string nomUtilisateur("Sans nom"); //On crée une case mémoire pour contenir une chaine de caractères
getline(cin, nomUtilisateur); //On remplit cette case avec toutela ligne que l'utilisateur a écrit
double piUtilisateur(-1.); //On crée une case mémoire pour stockerun nombre réel
cout << "Vous vous appelez " << nomUtilisateur << " et vous pensez que pivaut " << piUtilisateur << "." << endl;
return 0;
}
On retrouve les mêmes éléments qu'auparavant. Il y a cin et il y a le nom de la variable
(nomUtilisateur) sauf que, cette fois, ces deux éléments se retrouvent encadrés par des
parenthèses et séparés par une virgule au lieu des chevrons.
L'ordre des éléments entre les parenthèses est très important. Il faut absolument mettre cin en
premier !
Cette fois le nom ne sera pas tronqué lors de la lecture et notre ami Albert pourra utiliser notre
programme sans soucis.
Quel est votre nom ?
Albert Einstein
Combien vaut pi ?
3.14
Vous vous appelez Albert Einstein et vous pensez que pi vaut 3.14.
Demandez d'abord la valeur de pi
Si l'on utilise d'abord cin >> puis getline(), par exemple pour demander la valeur de pi avant de
demander le nom, le code ne fonctionne pas. L'ordinateur ne demande pas son nom à
l'utilisateur et affiche n'importe quoi.
Pour pallier ce problème, il faut ajouter la lignecin.ignore()après l'utilisation des chevrons.
#include <iostream>
55
#include <string>
int main()
double piUtilisateur(-1.); //On crée une case mémoire pour stocker unnombre réel
cin.ignore();
string nomUtilisateur("Sans nom"); //On crée une case mémoire pour contenir une chaine de caractères
getline(cin, nomUtilisateur); //On remplit cette case avec toute la ligne que l'utilisateur a écrit
cout << "Vous vous appelez " << nomUtilisateur << " et vous pensez que pivaut " << piUtilisateur << "." << endl;
return 0;
}
Avec cela, plus de souci.
Quand on mélange l'utilisation des chevrons et de getline(), il faut toujours placer l'instruction
cin.ignore() après la ligne cin>>a. C'est une règle à apprendre.
Voyons maintenant ce que l'on peut faire avec des variables, par exemple additionner deux
nombres.
56
Je vous ai expliqué dans l'introduction de ce chapitre que la mémoire de l'ordinateur
ressemble, dans sa manière de fonctionner, à celle d'une calculatrice. Ce n'est pas la seule
similitude. On peut évidemment effectuer des opérations de calcul sur un ordinateur. Et cela
se fait en utilisant des variables.
int unNombre(0); //Je crée une case mémoire nommée 'unNombre' et qui contient le nombre 0
57
#include <iostream>
int main()
cout << "a vaut : " << a << " et b vaut : " << b << endl;
cout << "a vaut : " << a << " et b vaut : " << b << endl;
return 0;
}
Avez-vous testé ? Non ? N'oubliez pas qu'il est important de tester les codes proposés pour
bien comprendre. Bon, comme je suis gentil, je vous donne le résultat.
a vaut : 4 et b vaut : 5
Affectation !
a vaut : 5 et b vaut : 5
Exactement ce que je vous avais prédit.
La valeur debn'a pas changé ! Il est important de se rappeler que, lors d'une affectation, seule
la variable à gauche du symbole=est modifiée.
Cela ne veut pas dire que les deux variables sont égales ! Juste que le contenu de celle de
droite est copié dans celle de gauche.
C'est un bon début mais on est encore loin d'une calculatrice. Il nous manque… les opérations
!
Commençons avec l'opération la plus simple : l'addition bien sûr. Et je pense que je ne vais
pas trop vous surprendre en vous disant qu'on utilise le symbole +.
58
C'est vraiment très simple à faire :
#include <iostream>
int main()
resultat = a + b;
return 0;
}
Sur votre écran vous devriez voir :
5 + 8 = 13
Ce n'est pas tout, il existe encore quatre autres opérations. Je vous ai mis un résumé des
possibilités dans un tableau récapitulatif.
59
Opération Symbole Exemple
Addition + resultat = a + b;
Soustraction - resultat = a - b;
Multiplication * resultat = a * b;
Division / resultat = a / b;
Modulo % resultat = a % b;
Je vous ai présenté comment modifier des variables. J'espère que vous avez bien compris !
Parce qu'on va faire le contraire, en quelque sorte. Je vais vous montrer comment déclarer des
variables non modifiables.
En termes techniques, on parle de constantes. Cela fait beaucoup de termes techniques pour
un seul chapitre mais je vous promets que, dans la suite, cela va se calmer.
Euh, mais à quoi peuvent bien servir des variables non modifiables ?
60
Ah, je savais que vous alliez poser cette question. Je vous ai donc préparé une réponse aux
petits oignons.
Prenons le futur jeu vidéo révolutionnaire que vous allez créer. Comme vous êtes très forts, je
pense qu'il y aura plusieurs niveaux, disons 10. Eh bien ce nombre de niveaux ne va jamais
changer durant l'exécution du programme. Entre le moment où l'utilisateur lance le jeu et le
moment où il le quitte, il y a en permanence 10 niveaux dans votre jeu. Ce nombre est
constant. En C++, on pourrait donc créer une variable nombreNiveaux qui serait une constante.
Ce n'est, bien sûr, pas le seul exemple. Pensez à une calculatrice, qui aura besoin de la
constante ππ, ou bien à un jeu dans lequel les personnages tombent et où il faudra utiliser la
constante d'accélération de la pesanteur g=9.81g=9.81 (environ), et ainsi de suite.
Ces valeurs ne vont jamais changer.
ππ vaudra toujours 3.143.14 (environ) et l'accélération sur Terre est partout identique. Ce
sont des constantes. On peut même ajouter que ce sont des constantes dont on connaît la
valeur lors de la rédaction du code source.
Mais ce n'est pas tout. Il existe aussi des variables dont la valeur ne change jamais mais dont
on ne connaît pas la valeur à l'avance. Prenons le résultat d'une opération dans une
calculatrice. Une fois que le calcul est effectué, le résultat ne change plus. La variable qui
contient le résultat est donc une constante.
C'est très simple. On déclare une variable normale et on ajoute le mot-clé const 1A entre le
type et le nom.
Déclarez toujours avec const tout ce qui peut l'être. Cela permet non seulement d'éviter des
erreurs d'inattention lorsque l'on programme, mais cela peut aussi aider le compilateur à créer
un programme plus efficace.
Vous verrez, on reparlera des constantes dans les prochains chapitres. En attendant, préparez-
vous pour votre premier exercice.
Je crois qu'on a enfin toutes les clés en main pour réaliser votre premier vrai programme.
Dans l'exemple précédent, le programme effectuait l'addition de deux nombres fixés à
61
l'avance. Il serait bien mieux de demander à l'utilisateur quels nombres il veut additionner !
Voilà donc le sujet de notre premier exercice : demander deux nombres à l'utilisateur, calculer
la somme de ces deux nombres et finalement afficher le résultat.
Rassurez-vous, je vais vous aider, mais je vous invite à essayer par vous-mêmes avant de
regarder la solution. C'est le meilleur moyen d'apprendre.
Dans un premier temps, il faut toujours réfléchir aux variables qu'il va falloir utiliser dans le
code.
On peut donc déjà écrire un bout de notre programme, c'est-à-dire la structure de base et la
déclaration des variables.
#include <iostream>
int main()
//…
return 0;
}
L'étape suivante consiste à demander des nombres à l'utilisateur. Je pense que vous vous en
souvenez encore, cela se fait grâce àcin >>. On peut donc aller plus loin et écrire :
#include <iostream>
int main()
62
{
cout << "Bienvenue dans le programme d'addition a+b !" << endl;
cout << "Donnez une valeur pour a : "; //On demande le premier nombre
cin >> a;
cout << "Donnez une valeur pour b : "; //On demande le deuxième nombre
cin >> b;
//…
return 0;
}
Il ne nous reste plus qu'à effectuer l'addition et afficher le résultat. Il nous faut donc une
variable. Comme le résultat du calcul ne va pas changer, nous pouvons (et même devons)
déclarer cette variable comme une constante.
Nous allons remplir cette constante, que j'appelleresultat, avec le résultat du calcul.
Finalement, pour effectuer l'addition, c'est bien sûr le symbole + qu'il va falloir utiliser.
#include <iostream>
int main()
63
cout << "Bienvenue dans le programme d'addition a+b !" << endl;
cout << "Donnez une valeur pour a : "; //On demande le premier nombre
cin >> a;
cout << "Donnez une valeur pour b : "; //On demande le deuxième nombre
cin >> b;
cout << a << " + " << b << " = " << resultat << endl;
return 0;
}
Mmmh, cela a l'air rudement bien tout cela ! Compilons et testons pour voir.
Bienvenue dans le programme d'addition a+b !
Donnez une valeur pour a : 123.784
Donnez une valeur pour b : 51.765
123.784 + 51.765 = 175.549
Magnifique ! Exactement ce qui était prévu !
Bon, j'ai assez travaillé. À vous maintenant de programmer. Je vous propose de vous entraîner
en modifiant cet exercice. Voici quelques idées:
•
calculer le produit de a et b plutôt que leur somme ;
• faire une opération plus complexe comme a×b+c ;
• demander deux nombres entiers et calculer leur quotient et le reste de la division.
Bon courage et amusez-vous bien !
Après cet exercice, vous savez manipuler toutes les opérations de base. C'est peut-être
surprenant pour vous mais il n'en existe pas d'autres ! Avec ces 5 opérations, on peut tout
faire, même des jeux vidéo comme ceux présentés dans le chapitre d'introduction.
64
Il existe quand même quelques variantes qui, j'en suis sûr, vont vous plaire.
IV.4.1. L'incrémentation
Une des opérations les plus courantes en informatique consiste à ajouter « 1 » à une variable.
Pensez par exemple aux cas suivants :
++nombreJoueur;
Vous trouvez peut-être cela ridicule mais je suis sûr que vous allez rapidement adorer ce
genre de choses !
Cette astuce est tellement utilisée qu'elle figure même dans le nom du langage ! Oui, oui, C++
veut en quelque sorte dire « C incrémenté » ou, dans un français plus correct, « C amélioré ».
Ils sont fous ces informaticiens !
IV.4.2. La décrémentation
65
int nombreJoueur(4); //Il y a 4 joueurs dans la partie
Bon. Ajouter ou enlever 1, c'est bien mais ce n'est pas non plus suffisant pour tout faire. Il
existe des raccourcis pour toutes les opérations de base.
Si l'on souhaite diviser une variable par 3, on devrait écrire, en version longue :
double nombre(456);
nombre = nombre / 3;
double nombre(456);
nombre /= 3;
#include <iostream>
int main()
66
double nombre(5.3);
return 0;
}
Ces opérations sont utiles quand il faut ajouter ou soustraire autre chose que 1.
Vous en voulez encore ? Ah je vois, vous n'êtes pas satisfaits de votre calculatrice. C'est vrai
qu'elle est encore un peu pauvre, elle ne connaît que les opérations de base. Pas vraiment
génial pour la super-super-calculatrice qu'est votre ordinateur.
➢ L'en-tête cmath
Pour avoir accès à plus de fonctions mathématiques, il suffit d'ajouter une ligne en tête de
votre programme, comme lorsque l'on désire utiliser des variables de type string. La directive à
insérer est :
#include <cmath>
Jusque là, c'est très simple. Et dans cmath il y a « math », ce qui devrait vous réjouir. On est
sur la bonne voie.
Je vais vous présenter comment utiliser quelques fonctions mathématiques en C++. Il se peut
très bien que vous ne sachiez pas ce que sont ces fonctions : ce n'est pas grave, elles ne vous
seront pas utiles dans la suite du cours. Vous saurez ce qu'elles représentent quand vous aurez
fait un peu plus de maths.
Commençons avec une fonction utilisée très souvent, la racine carrée. En anglais, racine
carrée se dit square root et, en abrégé, on écrit parfois sqrt. Comme le C++ utilise l'anglais,
c'est ce mot là qu'il va falloir retenir et utiliser.
Pour utiliser une fonction mathématique, on écrit le nom de la fonction suivi, entre
parenthèses, de la valeur à calculer. On utilise alors l'affectation pour stocker le résultat dans
une variable.
resultat = fonction(valeur);
C'est comme en math quand on écrit y=f(x)y=f(x). Il faut juste se souvenir du nom
compliqué des fonctions. Pour la racine carrée, cela donnerait resultat = sqrt(valeur);.
N'oubliez pas le point-virgule à la fin de la ligne !
Prenons un exemple complet, je pense que vous allez comprendre rapidement le principe.
67
#include <iostream>
int main()
cout << "La racine de " << nombre << " est " << resultat << endl;
return 0;
}
Voyons ce que cela donne.
La racine de 16 est 4
Votre ordinateur calcule correctement. Mais je ne pense pas que vous en doutiez.
68
Nom de la fonction Symbole Fonction Mini-exemple
Les fonctions trigonométriques (sin(),cos(),… ) utilisent les radians comme unité d'angles.
Il existe encore beaucoup d'autres fonctions ! Je ne vous ai mis que les principales pour ne pas
qu'on se perde.
On parle de mathématiques, ces fonctions ne sont donc utilisables qu'avec des variables qui
représentent des nombres (double,intetunsigned int). Prendre la racine carrée d'une lettre ou
calculer le cosinus d'une phrase n'a de toute façon pas de sens.
69
Je déclare une variable (constante) pour mettre le 4, une autre pour stocker le 5 et finalement
une dernière pour le résultat. Rien de nouveau jusque là. J'utilise la fonction pow() pour
effectuer le calcul et j'utilise le symbole = pour initialiser la variable resulta tavec la valeur
calculée par la fonction.
Nous pouvons donc reprendre l'exercice précédent et remplacer l'addition par notre nouvelle
amie, la fonction puissance. Je vous laisse essayer.
Voici ma version :
#include <iostream>
int main()
cout << "Bienvenue dans le programme de calcul de a^b !" << endl;
cout << "Donnez une valeur pour a : "; //On demande le premier nombre
cin >> a;
cout << "Donnez une valeur pour b : "; //On demande le deuxième nombre
cin >> b;
70
//De l'initialisation d'une variable
cout << a << " ^ " << b << " = " << resultat << endl;
return 0;
}
Vous avez fait la même chose ? Parfait ! Vous êtes de futurs champions du C++ ! Voyons
quand même ce que cela donne.
Bienvenue dans le programme de calcul de a^b !
Donnez une valeur pour a : 4
Donnez une valeur pour b : 5
4 ^ 5 = 1024
J'espère que vous êtes satisfaits avec toutes ces fonctions mathématiques. Je ne sais pas si
vous en aurez besoin un jour mais, si c'est le cas, vous saurez où en trouver une description.
En résumé
• Pour demander à l'utilisateur de saisir une information au clavier, on utilisecin >>
variable;. La valeur saisie sera stockée dans la variable.
• Il ne faut pas confondre le sens des chevrons cout <<etcin >>.
• On peut faire toutes sortes d'opérations mathématiques de base en C++ : addition,
soustraction, multiplication… Exemple :resultat = a + b;
• Les constantes sont des variables qu'on ne peut pas modifier une fois qu'elles ont été
créées. On utilise le mot const pour les définir.
• Pour ajouter 1 à la valeur d'une variable, on effectue ce qu'on appelle une
incrémentation :variable++;. L'opération inverse, appelée décrémentation, existe aussi.
• Si vous souhaitez utiliser des fonctions mathématiques plus complexes, comme la
racine carrée, il faut inclure l'en-tête <cmath>dans votre code et faire appel à la fonction
comme dans cet exemple :resultat = sqrt(100);
71
V. Utilisez les structures de contrôle
Les programmes doivent être capables de prendre des décisions. Pour y parvenir, les
développeurs utilisent ce qu'on appelle des structures de contrôle. Ce nom un peu barbare
cache en fait deux éléments que nous verrons dans ce chapitre :
• les conditions : elles permettent d'écrire dans le programme des règles comme « Si
ceci arrive, alors fais cela » ;
• les boucles : elles permettent de répéter plusieurs fois une série d'instructions.
Savoir manier les structures de contrôle est fondamental ! Bien que ce chapitre ne soit pas
réellement difficile, il faut faire attention à bien comprendre ces notions de base. Elles vous
serviront durant toute votre vie de développeurs C++ mais aussi dans d'autres langages car le
principe y est le même !
Les conditions
Pour qu'un programme soit capable de prendre des décisions, on utilise dans le code source
des conditions (on parle aussi de « structures conditionnelles »). Le principe est simple : vous
voulez que votre programme réagisse différemment en fonction des circonstances. Nous
allons découvrir ici comment utiliser ces fameuses conditions dans nos programmes C++.
Pour commencer, il faut savoir que les conditions permettent de tester des variables. Vous
vous souvenez de ces variables stockées en mémoire que nous avons découvertes au chapitre
précédent ? Eh bien nous allons maintenant apprendre à les analyser : « Est-ce que cette
variable est supérieure à 10 ? », « Est-ce que cette variable contient bien le mot de passe
secret ? », etc.
Pour effectuer ces tests, nous utilisons des symboles. Voici le tableau des symboles à
connaître par cœur :
Symbole Signification
== Est égal à
!= Est différent de
Faites très attention : en C++, il y a bien 2 symboles == pour tester l'égalité. Les débutants
oublient souvent cela et n'écrivent qu'un seul =, ce qui n'a pas la même signification.
Nous allons utiliser ces symboles pour effectuer des comparaisons dans nos conditions.
Il faut savoir qu'il existe en C++ plusieurs types de conditions pour faire des tests, mais la
plus importante, qu'il faut impérativement connaître, est sans aucun doute la condition if.
72
La condition if
Comme je vous le disais, les conditions permettent de tester des variables. Je vous propose
donc de créer un petit programme en même temps que moi et de faire des tests pour vérifier
que vous avez bien compris le principe.
#include <iostream>
int main()
int nbEnfants(2);
return 0;
}
Ce code-là ne fait rien pour le moment. Il se contente de déclarer une variable nbEnfants(qui
indique donc un nombre d'enfants), puis il s'arrête.
#include <iostream>
int main()
int nbEnfants(2);
73
if (nbEnfants > 0)
cout << "Vous avez des enfants, bravo !" << endl;
return 0;
}
Ce code affiche :
Vous avez des enfants, bravo !
Fin du programme
Regardez bien la ligne suivante :
if (nbEnfants > 0)
Elle effectue le test : « Si le nombre d'enfants est supérieur à 0 » (« if », en anglais, veut dire
« si »).
Si ce test est vérifié (donc si la personne a bien des enfants), alors l'ordinateur va lire les
lignes qui se trouvent entre les accolades : il va donc afficher le message « Vous avez des
enfants, bravo ! ».
Dans notre cas, si la personne n'a aucun enfant, on verra seulement ce message apparaître :
Fin du programme
Faites le test ! Changez la valeur de la variablenbEnfants, passez-la à 0 et regardez ce qui se
produit.
Heureusement, vous pouvez utiliser le mot-clé else qui signifie « sinon ». On va par exemple
afficher un autre message si la personne n'a pas d'enfant :
#include <iostream>
74
using namespace std;
int main()
int nbEnfants(0);
if (nbEnfants > 0)
cout << "Vous avez des enfants, bravo !" << endl;
else
cout << "Eh bien alors, vous n'avez pas d'enfant ?" << endl;
return 0;
}
Ce code affiche :
Eh bien alors, vous n'avez pas d'enfant ?
Fin du programme
... car j'ai changé la valeur de la variable nbEnfants au début, regardez bien.
Si vous mettez une valeur supérieure à 0, le message redeviendra celui que nous avons vu
avant !
Comment cela fonctionne-t-il ? C'est très simple en fait : l'ordinateur lit d'abord la condition
du if et se rend compte que la condition est fausse. Il vérifie si la personne a au moins 1 enfant
et ce n'est pas le cas.
L'ordinateur « saute » tout ce qui se trouve entre les premières accolades et tombe sur la ligne
else qui signifie « sinon ». Il effectue donc les actions indiquées après else
75
Condition if - else
#include <iostream>
int main()
int nbEnfants(2);
if (nbEnfants == 0)
cout << "Eh bien alors, vous n'avez pas d'enfant ?" << endl;
76
}
else if (nbEnfants == 1)
cout << "Alors, c'est pour quand le deuxieme ?" << endl;
else if (nbEnfants == 2)
cout << "Quels beaux enfants vous avez la !" << endl;
else
cout << "Bon, il faut arreter de faire des gosses maintenant !" << endl;
return 0;
}
Cela se complique ? Pas tant que cela.
77
Conditions
if - else if - else
La condition switch
En théorie, la condition if permet de faire tous les tests que l'on veut. En pratique, il existe
d'autres façons de faire des tests. La condition switch, par exemple, permet de simplifier
l'écriture de conditions qui testent plusieurs valeurs possibles pour une même variable.
Prenez par exemple le test que l'on vient de faire sur le nombre d'enfants :
A-t-il 0 enfant ?
A-t-il 1 enfant ?
A-t-il 2 enfants ?
...
On peut faire ce genre de tests avec des if...else if...else..., mais on peut faire la même chose
avec une condition switch qui, dans ce genre de cas, a tendance à rendre le code plus lisible.
Voici ce que donnerait le code précédent avec switch:
#include <iostream>
78
using namespace std;
int main()
int nbEnfants(2);
switch (nbEnfants)
case 0:
cout << "Eh bien alors, vous n'avez pas d'enfant ?" << endl;
break;
case 1:
cout << "Alors, c'est pour quand le deuxieme ?" << endl;
break;
case 2:
cout << "Quels beaux enfants vous avez la !" << endl;
break;
default:
cout << "Bon, il faut arreter de faire des gosses maintenant !" << endl;
break;
79
}
return 0;
}
Ce qui affiche :
Quels beaux enfants vous avez la !
La forme est un peu différente : on indique d'abord qu'on va analyser la variable
nbEnfants(ligne 9). Ensuite, on teste tous les cas (case) possibles : si la variable vaut 0, si elle
vaut 1, si elle vaut 2...
Les break sont obligatoires si on veut que l'ordinateur arrête les tests une fois que l'un d'eux a
réussi. En pratique, je vous conseille d'en mettre comme moi à la fin de chaque case.
Enfin, le default à la fin correspond au else(« sinon ») et s'exécute si aucun des tests précédents
n'est vérifié.
Switch ne permet de tester que l'égalité. Vous ne pouvez pas tester « Si le nombre d'enfants est
supérieur à 2 » avec switch: il faut dans ce cas utilise rif.
De plus, switch ne peut travailler qu'avec des nombres entiers (int, unsigned int, char). Il est
impossible de tester des nombres décimaux (double).switch est donc limité en termes de
possibilités mais cette instruction propose une écriture alternative parfois plus pratique dans
des cas simples.
Booléens et combinaisons de conditions
Allons un peu plus loin avec les conditions. Nous allons découvrir deux notions plus avancées
et néanmoins essentielles : les booléens et les combinaisons de conditions.
Les booléens
Vous vous souvenez du type bool? Ce type de données peut stocker deux valeurs :
1. true(vrai) ;
2. false(faux).
Ce type est souvent utilisé avec les conditions. Quand on y pense, c'est logique : une condition
est soit vraie, soit fausse. Une variable booléenne aussi.
Si je vous parle du typebool, c'est parce qu'on peut l'utiliser d'une façon un peu particulière
dans les conditions. Pour commencer, regardez ce code :
bool adulte(true);
if (adulte == true)
80
cout << "Vous etes un adulte !" << endl;
}
Cette condition, qui vérifie la valeur de la variableadulte, affiche un message si celle-ci vaut
vrai (true).
Vous vous demandez peut-être où je veux en venir ? En fait, il est possible d'omettre la partie
«== true» dans la condition, cela revient au même ! Regardez ce code, qui est équivalent :
bool adulte(true);
if (adulte)
}
L'ordinateur comprend que vous voulez vérifier si la variable booléenne vauttrue. Il n'est pas
nécessaire de rajouter «== true».
Je vous invite à utiliser cette notation raccourcie quand vous testerez des variables
booléennes. Cela vous aidera à clarifier votre code et à rendre certaines conditions plus «
digestes » à lire.
&& ET
|| OU
! NON
Test ET
Imaginons : on veut tester si la personne est adulte et si elle a au moins 1 enfant. On va donc
écrire :
81
Notez que j'aurais également pu écrire cette condition ainsi :if (adulte == true && nbEnfants >= 1).
Cependant, comme je vous l'ai expliqué un peu plus tôt, il est facultatif de préciser «== true»
sur les booléens et c'est une habitude que je vous invite à prendre.
Test OU
Pour faire un OU, on utilise les 2 signes||. Je dois avouer que ce signe n'est pas facilement
accessible sur nos claviers. Pour le taper sur un clavier AZERTY français, il faut appuyer sur
les touches Alt Gr + 6 . Sur un clavier belge, il faut appuyer sur les touches Alt Gr + & et
enfin, pour les Suisses, c'est la combinaison Alt Gr + 7 qu'il faut utiliser.
On peut par exemple tester si le nombre d'enfants est égal à 1 OU 2 :
if (nbEnfants == 1 || nbEnfants == 2)
Test NON
Il faut maintenant que je vous présente un dernier symbole : le point d'exclamation. En
informatique, le point d'exclamation signifie « Non ».
Vous devez mettre ce signe avant votre condition pour pouvoir dire « Si cela n'est pas vrai » :
if (!adulte)
Cela pourrait se traduire par « Si la personne n'est pas adulte ».
Les boucles
Les boucles vous permettent de répéter les mêmes instructions plusieurs fois dans votre
programme. Le principe est représenté en figure suivante.
• while;
• do ... while;
• for.
La boucle while
Cette boucle s'utilise comme ceci :
82
while (condition)
/* Instructions à répéter */
}
Tout ce qui est entre accolades sera répété tant que la condition est vérifiée.
Essayons de faire ce que j'ai dit plus tôt : on redemande le nombre d'enfants à l'utilisateur tant
que celui-ci est inférieur à 0. Ce genre de boucle permet de s'assurer que l'utilisateur rentre un
nombre correct.
int main()
cout << "Merci d'avoir indique un nombre d'enfants correct. Vous en avez " << nbEnfants << endl;
return 0;
}
Voici un exemple d'utilisation de ce programme :
Combien d'enfants avez-vous ?
-3
Combien d'enfants avez-vous ?
-5
Combien d'enfants avez-vous ?
2
Merci d'avoir indique un nombre d'enfants correct. Vous en avez 2
83
Tant que vous saisissez un nombre négatif, la boucle recommence. En effet, elle teste while
(nbEnfants < 0), c'est-à-dire « Tant que le nombre d'enfants est inférieur à 0 ». Dès que le
nombre devient supérieur ou égal à 0, la boucle s'arrête et le programme continue après
l'accolade fermante.
Vous noterez que j'ai initialisé la variable nbEnfants à -1. En effet, pour que l'ordinateur veuille
bien entrer une première fois dans la boucle, il faut faire en sorte que la condition soit vraie la
première fois.
do
/* Instructions */
} while (condition);
Notez bien la présence du point-virgule tout à la fin !
int main()
int nbEnfants(0);
do
cout << "Merci d'avoir indique un nombre d'enfants correct. Vous en avez " << nbEnfants << endl;
84
return 0;
}
Le principe est le même, le programme a le même comportement. Le gros intérêt de do ... while
est qu'on s'assure que la boucle sera lue au moins une fois.
D'ailleurs, du coup, il n'est pas nécessaire d'initialiser nbEnfants à -1 (c'est le principal avantage
que procure cette solution). En effet, le nombre d'enfants est initialisé ici à 0 (comme on a
l'habitude de faire) et, comme la condition n'est testée qu'après le premier passage de la
boucle, les instructions sont bien lues au moins une fois.
La boucle for
Ce type de boucle, que l'on retrouve fréquemment, permet de condenser :
•
une initialisation ;
• une condition ;
• une incrémentation.
Voici sa forme :
}
Regardons un exemple concret qui affiche des nombres de 0 à 9 :
int main()
int compteur(0);
return 0;
85
Ce code affiche :
0
1
2
3
4
5
6
7
8
9
On retrouve sur la ligne duforles 3 instructions que je vous ai indiquées :
•
Une initialisation (compteur = 0) : la variablecompteurest mise à 0 au tout début de la
boucle. Notez que cela avait été fait à la ligne immédiatement au-dessus, ce n'était
donc pas vraiment nécessaire ici.
• Une condition (compteur < 10) : on vérifie que la variablecompteurest inférieure à 10 à
chaque nouveau tour de boucle.
• Une incrémentation (compteur++) : à chaque tour de boucle, on ajoute 1 à la
variablecompteur! Voilà pourquoi on voit s'afficher à l'écran des nombres de 0 à 9.
Vous pouvez faire autre chose qu'une incrémentation si vous le désirez. La dernière section
duforest réservée à la modification de la variable et vous pouvez donc y faire une
décrémentation (compteur--) ou avancer de 2 en 2 (compteur += 2), etc.
Notez qu'il est courant d'initialiser la variable directement à l'intérieur dufor, comme ceci :
int main()
return 0;
}
La variable n'existe alors que pendant la durée de la bouclefor. C'est la forme la plus courante
de cette boucle. On ne déclare la variable avant leforque si on en a besoin plus tard, ce qui est
un cas assez rare.
86
• Les conditions permettent de tester la valeur des variables et de modifier le
comportement du programme en conséquence.
• La condition de typeif(si) ...else if(sinon si) ...else(sinon) est la plus courante.
• La conditionswitch, plus spécifique, permet de tester les différentes valeurs possibles
d'une seule variable.
• Les boucles permettent de répéter les mêmes instructions plusieurs fois.
• On distingue trois types de boucles :while,do... whileetfor.
• La boucleforest généralement utilisée lorsqu'on sait combien de fois on souhaite
répéter les instructions, tandis quewhileetdo... whilesont plutôt utilisées lorsqu'on
souhaite répéter des instructions jusqu'à ce qu'une condition spécifique soit vérifiée.
87
Découpez votre programme en fonctions
Nous venons de voir comment faire varier le déroulement d'un programme en utilisant des
boucles et des branchements. Avant cela, je vous ai parlé des variables. Ce sont des éléments
qui se retrouvent dans tous les langages de programmation. C'est aussi le cas de la notion que
nous allons aborder dans ce chapitre : les fonctions.
Tous les programmes C++ exploitent des fonctions et vous en avez déjà utilisé plusieurs, sans
forcément le savoir.
Le but des fonctions est de découper son programme en petits éléments réutilisables, un peu
comme des briques. On peut les assembler d'une certaine manière pour créer un mur, ou d'une
autre manière pour faire un cabanon ou même un gratte-ciel. Une fois que les briques sont
créées, le programmeur « n'a plus qu'à » les assembler.
Commençons par créer des briques. Nous apprendrons à les utiliser dans un deuxième temps.
#include <iostream>
return 0;
Si je vous dis tout cela, vous devez vous douter que l'on peut écrire d'autres fonctions et donc
avoir un programme découpé en plusieurs modules indépendants.
88
Imaginons que nous voulions créer un jeu vidéo 3D. Comme c'est quand même assez
complexe, le code source va nécessiter plusieurs dizaines de milliers de lignes ! Si l'on garde
tout dans une seule fonction, il va être très difficile de s'y retrouver. Il serait certainement plus
simple d'avoir dans un coin un morceau de code qui fait bouger un personnage, ailleurs un
autre bout de code qui charge les niveaux, etc. Découper son programme en fonctions permet
de s'organiser.
En plus, si vous êtes plusieurs développeurs à travailler sur le même programme, vous
pourrez vous partager plus facilement le travail : chacun s'attelle une fonction différente.
Vous vous souvenez de pow()? La fonction qui permet de calculer des puissances ? En utilisant
le nouveau vocabulaire, on peut dire que cette fonction :
89
Vous en avez déjà fait l'expérience, on peut utiliser cette fonction plusieurs fois. Cela
implique que l'on n'est pas obligé de copier le code qui se trouve à l'intérieur de la
fonction pow()chaque fois que l'on souhaite effectuer un calcul de puissance.
type nomFonction(arguments)
}
On retrouve les trois éléments dont je vous ai déjà parlé, auxquels s'ajoute le nom de la
fonction.
90
b)etla fonction double addition(double a, double b). Les deux fonctions ont le même nom mais l'une
travaille avec des entiers et l'autre avec des nombres réels.
Créons donc des fonctions !
return valeur;
}
Il n'y a pas de point-virgule ! Ni après la déclaration, ni après l'accolade fermante.
Analysons ce code en détail. Il y a deux lignes vraiment nouvelles pour vous.
Avec ce que je vous ai expliqué, vous devriez comprendre la première ligne. On déclare une
fonction nomméeajouteDeuxqui reçoit un nombre entier en argument et qui, une fois qu'elle a
terminé, renvoie un autre nombre entier :
La fonction reçoit
un nombre en entrée et produit un autre nombre en sortie
91
Toutes les lignes suivantes utilisent des choses déjà connues, saufreturn valeur;. Si vous vous
posez des questions sur ces lignes, je vous invite à relire le chapitre sur l'utilisation de la
mémoire.
#include <iostream>
return valeur;
int main()
int a(2),b(2);
92
return 0;
}
On retrouve la syntaxe que l'on connaissait déjà :résultat = fonction(argument). Facile, pour ainsi
dire !
Vous avez essayé le programme ? Voici ce que cela donne :
Valeur de a : 2
Valeur de b : 2
Valeur de a : 2
Valeur de b : 4
Après l'appel à la fonction, la variableba été modifiée. Tout fonctionne donc comme annoncé.
Plusieurs paramètres
Nous ne sommes pas encore au bout de nos peines. Il y a des fonctions qui prennent plusieurs
paramètres, commepow()etgetline()par exemple.
Pour passer plusieurs paramètres à une fonction, il faut les séparer par des virgules.
return a+b;
return a*b*c;
}
La première de ces fonctions calcule la somme des deux nombres qui lui sont fournis, alors
que la deuxième calcule le produit des trois nombres reçus.
Vous pouvez bien sûr écrire des fonctions qui prennent des arguments de type différent.
Pas d'arguments
À l'inverse, on peut aussi créer des fonctions sans arguments. Il suffit de ne rien écrire entre
les parenthèses !
string demanderNom()
93
{
string nom;
return nom;
}
Même s'il est vrai que ce type de fonctions est plus rare, je suis sûr que vous trouverez plein
d'exemples par la suite !
void direBonjour()
int main()
direBonjour();
return 0;
94
Notez également qu'il n'est pas possible de renvoyer plus qu'une valeur. Une fonction produit
toujours au maximum un résultat.
Avec ce dernier point, nous avons fait le tour de la théorie. Dans la suite du chapitre, je vous
propose quelques exemples et un super schéma récapitulatif. Ce n'est pas le moment de partir.
Quelques exemples
Le carré
Commençons avec un exemple simple : calculer le carré d'un nombre. Cette fonction reçoit un
nombrexen argument et calcule la valeur de x2x2.
#include <iostream>
double carre(double x)
double resultat;
resultat = x*x;
return resultat;
int main()
95
cout << "Le carre de " << nombre << " est " << carreNombre << endl;
return 0;
}
Je vous avais promis un schéma, le voilà. Voyons ce qui se passe dans ce programme et dans
quel ordre sont exécutées les lignes (figure suivante).
Il y a une chose dont il faut absolument se rappeler : les valeurs des variables transmises aux
fonctions sont copiées dans de nouvelles cases mémoires. La fonction carre()n'agit donc pas
sur les variables déclarées dans la fonction main(). Elle travaille uniquement avec ses propres
cases mémoires.
Ce n'est que lors du returnque les variables demain()sont modifiées c'est-à-dire ici la
variable carreNombre. La variable nombrereste inchangée lors de l'appel à la fonction.
#include <iostream>
96
using namespace std;
double carre(double x)
double resultat;
resultat = x*x;
return resultat;
int main()
cout << "Le carre de " << i << " est : " << carre(i) << endl;
return 0;
}
On écrit une seule fois la formule du calcul du carré et on utilise ensuite vingt fois cette «
brique ». Ici, le calcul est simple mais, dans bien des cas, utiliser une fonction raccourcit
grandement le code !
#include <iostream>
97
double carre(double x)
double nombre;
nombre = x*x;
return nombre;
int main()
cout << "Le carre de " << nombre << " est " << carreNombre << endl;
return 0;
}
Comme vous pouvez le voir, il existe une variable nombredans la fonction main()et une autre
dans la fonction carre(). Le compilateur ne va pas sourciller et ce code fait exactement la même
chose que le précédent. Il n'y a pas de confusion possible entre les deux variables puisque le
compilateur s'occupe d'une fonction à la fois et ne verra donc pas qu'il y a deux variables au
même nom.
98
Une fonction à deux arguments
Avant de terminer cette section, voici un dernier exemple. Cette fois, je vous propose une
fonction utilisant deux arguments. Nous allons dessiner un rectangle d'étoiles * dans la
console. La fonction a besoin de deux arguments : la largeur et la hauteur du rectangle.
#include <iostream>
int main()
99
cin >> hauteur;
dessineRectangle(largeur, hauteur);
return 0;
}
Une fois compilé ce programme s'exécute et donne par exemple :
Largeur du rectangle : 16
Hauteur du rectangle : 3
****************
****************
****************
Voilà la première version d'un logiciel de dessin révolutionnaire !
Cette fonction ne fait qu'afficher du texte. Elle n'a donc pas besoin de renvoyer quelque chose.
C'est pour cela qu'elle est déclarée avec le type void.
On peut facilement modifier la fonction pour qu'elle renvoie la surface du rectangle. À ce
moment-là, il faudra qu'elle renvoie un int.
•
afficher un message d'erreur si la hauteur ou la largeur est négative ;
• ajouter un argument pour le symbole à utiliser dans le dessin.
Amusez-vous bien. Il est important de bien maîtriser tous ces concepts.
Prenons une fonction simple qui ajoute simplement 2 à l'argument fourni. Vous commencez à
bien la connaître. Je l'ai donc modifiée un poil.
int ajouteDeux(int a)
a+=2;
return a;
}
Utiliser += ici est volontairement bizarre ! Vous verrez tout de suite pourquoi.
100
Testons donc cette fonction. Je pense ne rien vous apprendre en vous proposant le code
suivant :
#include <iostream>
int ajouteDeux(int a)
a+=2;
return a;
int main()
resultat = ajouteDeux(nombre);
cout << "Le nombre original vaut : " << nombre << endl;
cout << "Le resultat vaut : " << resultat << endl;
return 0;
}
Cela donne sans surprise :
Le nombre original vaut : 4
Le resultat vaut : 6
L'étape intéressante est bien sûr ce qui se passe à la ligneresultat = ajouteDeux(nombre);. Vous
vous rappelez les schémas de la mémoire ? Il est temps de les ressortir.
101
2. Le programme alloue un nouvel espace dans la mémoire et y écrit la valeur4. Cet
espace mémoire possède l'étiquette a, le nom de la variable dans la fonction.
3. Le programme entre dans la fonction.
4. Le programme ajoute2 à la variable a.
5. La valeur de aest ensuite copiée et affectée à la variable resultat, qui vaut donc
maintenant6.
6. On sort alors de la fonction.
Ce qui est important, c'est que la variable nombreest copiée dans une nouvelle case mémoire.
On dit que l'argument aest passé par valeur. Lorsque le programme se situe dans la fonction,
la mémoire ressemble donc à ce qui se trouve dans le schéma :
On se retrouve donc avec trois cases dans la mémoire. L'autre élément important est que la
variable nombrereste inchangée.
Si j'insiste sur ces points, c'est bien sûr parce que l'on peut faire autrement.
102
Plutôt que de copier la valeur de nombredans la variablea, il est possible d'ajouter une «
deuxième étiquette » à la variable nombreà l'intérieur de la fonction. Et c'est bien sûr une
référence qu'il faut utiliser comme argument de la fonction.
a+=2;
return a;
}
Lorsque l'on appelle la fonction, il n'y a plus de copie. Le programme donne simplement un
alias à la variablenombre. Jetons un coup d'œil à la mémoire dans ce cas :
Cette fois, la variable aet la variable nombresont confondues. On dit que l'argument aest passé
par référence.
103
Cela permet à la fonction ajouteDeux()de modifier ses arguments ! Elle pourra ainsi avoir une
influence durable sur le reste du programme. Essayons pour voir. Reprenons le programme
précédent, mais avec une référence comme argument. On obtient cette fois :
Le nombre original vaut : 6
Le resultat vaut : 6
Que s'est-il passé ? C'est à la fois simple et compliqué.
Comme aet la variable nombrecorrespondent à la même case mémoire, faire a+=2a modifié la
valeur denombre!
Utiliser des références peut donc être très dangereux. C'est pour cela qu'on ne les utilise que
lorsqu'on en a réellement besoin.
b = temporaire; //Et on utilise la valeur sauvegardée pour mettre l'ancienne valeur de 'a' dans 'b'
int main()
cout << "a vaut " << a << " et b vaut " << b << endl;
cout << "a vaut " << a << " et b vaut " << b << endl;
104
return 0;
}
Ce code donne le résultat suivant :
a vaut 1.2 et b vaut 4.5
a vaut 4.5 et b vaut 1.2
Les valeurs des deux variables ont été échangées.
Si l'on n'utilisait pas un passage par référence, ce seraient alors des copies des arguments qui
seraient échangées, et non les vrais arguments. Cette fonction serait donc inutile.
Je vous invite à tester cette fonction avec et sans les références. Vous verrez ainsi précisément
ce qui se passe.
A priori, le passage par référence peut vous sembler obscur et compliqué. Vous verrez par la
suite qu'il est souvent utilisé. Vous pourrez toujours revenir lire cette section plus tard si les
choses ne sont pas encore vraiment claires dans votre esprit.
Le passage par référence offre un gros avantage sur le passage par valeur : aucune copie n'est
effectuée. Imaginez une fonction recevant en argument unstring. Si votre chaîne de caractères
contient un très long texte (la totalité de ce livre par exemple !), alors la copier va prendre du
temps même si tout cela se passe uniquement dans la mémoire de l'ordinateur. Cette copie est
totalement inutile et il serait donc bien de pouvoir l'éliminer pour améliorer les performances
du programme.
Et c'est là que vous me dites : « utilisons un passage par référence ! ». Oui, c'est une bonne
idée. En utilisant un passage par référence, aucune copie n'est effectuée. Seulement, cette
manière de procéder a un petit défaut : elle autorise la modification de l'argument. Eh oui,
c'est justement dans ce but que les références existent.
}
La solution est d'utiliser ce que l'on appelle un passage par référence constante. On évite la
copie en utilisant une référence et l'on empêche la modification de l'argument en le déclarant
constant.
105
void f1(string const& texte); //Pas de copie et pas de modification possible
}
Pour l'instant, cela peut vous sembler obscur et plutôt inutile. Dans la partie II de ce cours,
nous aborderons la programmation orientée objet et nous utiliserons très souvent cette
technique. Vous pourrez toujours revenir lire ces lignes à ce moment-là.
Le C++ permet de découper son programme en plusieurs fichiers sources. Chaque fichier
contient une ou plusieurs fonctions. On peut alors inclure les fichiers, et donc les fonctions,
dont on a besoin dans différents projets. On a ainsi réellement des briques séparées utilisables
pour construire différents programmes.
•un fichier source dont l'extension est.cpp: il contient le code source de la fonction ;
• un fichier d'en-tête dont l'extension est.h: il contient uniquement la description de la
fonction, ce qu'on appelle le prototype de la fonction.
Créons donc ces deux fichiers pour notre célèbre fonctionajouteDeux():
return valeur;
}
Le fichier source
C'est le plus simple des deux. Passez par les menusFile>New>File. Choisissez ensuiteC/C++
source(figure suivante).
106
Un fichier source
Cliquez ensuite surGo. Comme lors de la création du projet, le programme vous demande
alors si vous faites du C ou du C++. ChoisissezC++bien sûr !
Finalement, on vous demande le nom du fichier à créer. Comme pour tout, il vaut mieux
choisir un nom intelligent pour ses fichiers. On peut ainsi mieux s'y retrouver. Pour la
fonction ajouteDeux(), je choisis le nom math.cppet je place le fichier dans le même dossier que
mon fichier main.cpp.
107
Sélection des
options pour le fichier source
Cliquez surFinish. Votre fichier source est maintenant créé. Passons au fichier d'en-tête.
Le fichier d'en-tête
Le début est quasiment identique. Passez par les menusFile>New>File. Sélectionnez
ensuiteC/C++ header(figure suivante).
108
Création d'un fichier d'en-tête
Dans la fenêtre suivante, indiquez le nom du fichier à créer. Il est conseillé de lui donner le
même nom qu'au fichier source mais avec une extension .hau lieu de.cpp. Dans notre cas, ce
sera donc math.h. Placez le fichier dans le même dossier que les deux autres.
Ne touchez pas le champ juste en-dessous et n'oubliez pas de cocher toutes les options :
109
Sélection
des options pour le fichier d'en-tête
Une fois que les deux fichiers sont créés, vous devriez les voir apparaître dans la colonne de
gauche de Code::Blocks :
Le fichier source
Je vous ai dit que le fichier source contenait la déclaration de la fonction. C'est un des
éléments.
110
L'autre est plus compliqué à comprendre. Le compilateur a besoin de savoir que les
fichiers.cppet.hont un lien entre eux. Il faut donc commencer le fichier par la ligne suivante :
#include "math.h"
Vous reconnaissez certainement cette ligne. Elle indique que l'on va utiliser ce qui se trouve
dans le fichiermath.h.
Il faut utiliser ici des guillemets " et non des chevrons < et > comme vous en aviez l'habitude
jusque là.
Le fichiermath.cppau complet est donc :
#include "math.h"
return valeur;
}
Le fichier d'en-tête
Si vous regardez le fichier qui a été créé, il n'est pas vide ! Il contient trois lignes mystérieuses
:
#ifndef MATH_H_INCLUDED
#define MATH_H_INCLUDED
#endif // MATH_H_INCLUDED
Ces lignes sont là pour empêcher le compilateur d'inclure plusieurs fois ce fichier. Le
compilateur n'est parfois pas très malin et risque de tourner en rond. Cette astuce évite donc
de se retrouver dans cette situation. Il ne faut donc pas toucher ces lignes et surtout, écrire tout
le code entre la deuxième et la troisième.
Le texte en majuscules sera différent pour chaque fichier. C'est le texte qui apparaît dans le
champ que nous n'avons pas modifié lors de la création du fichier. Si vous n'utilisez pas
Code::Blocks, vous n'aurez peut-être pas automatiquement ces lignes dans vos fichiers. Il faut
alors les ajouter à la main. Le mot en majuscule doit être le même sur les trois lignes où il
apparaît et chaque fichier doit utiliser un mot différent.
111
Dans ce fichier, il faut mettre ce qu'on appelle le prototype de la fonction. C'est la première
ligne de la fonction, celle qui vient avant les accolades. On copie le texte de cette ligne et on
ajoute un point-virgule à la fin.
C'est donc très court. Voici ce que nous obtenons pour notre fonction :
#ifndef MATH_H_INCLUDED
#define MATH_H_INCLUDED
#endif // MATH_H_INCLUDED
N'oubliez pas le point-virgule ici !
Et c'est tout dans le cas le plus simple. Si vous utilisez des variables plus compliquées en
argument comme des strings (cela vaut aussi pour les tableaux, concept que nous verrons dans
le prochain chapitre), il faut ajouter la ligne d'inclusion#include <string>avant le prototype. On
aura ainsi:
#ifndef MATH_H_INCLUDED
#define MATH_H_INCLUDED
#include <string>
#endif // MATH_H_INCLUDED
L'autre élément important est l'ajout de std::devant le mot string. Il s'agit de la marque d'un
espace de nom, concept qui sera abordé plus loin dans ce cours. Si vous êtes attentifs, vous
aurez remarqué que stdapparaît dans tous nos fichiers sources via la ligne using namespace std.
Comme il n'y a pas de tel ligne ici (et qu'il est très vivement déconseillé de la mettre dans un
fichier d'en-tête), il nous faut utiliser le nom complet du type stringqui est std::string. Vous
verrez d'autres exemples de types de variables aux noms complexes plus loin dans le cours.
Pour l'instant, std::stringest le seul cas spécial.
Il ne nous reste qu'une seule chose à faire : inclure tout cela dans le fichier main.cpp. Si on ne le
fait pas, le compilateur ne saura pas où trouver la fonction ajouteDeux()lorsqu'on essaiera de
l'utiliser. Il faut donc ajouter la ligne :
112
#include "math.h"
au début de notre programme. Cela donne :
#include <iostream>
#include "math.h"
int main()
int a(2),b(2);
return 0;
}
On inclut toujours le fichier d'en-tête (.h), jamais le fichier source (.cpp).
Et voilà ! Nous avons maintenant réellement des briques séparées utilisables dans plusieurs
programmes. Si vous voulez utiliser la fonctionajouteDeux()dans un autre projet, il vous suffira
de copier les fichiersmath.cppetmath.h.
On peut bien sûr mettre plusieurs fonctions par fichier. On les regroupe généralement par
catégories : les fonctions mathématiques dans un fichier, les fonctions pour l'affichage d'un
menu dans un autre fichier et celles pour le déplacement d'un personnage de jeu vidéo dans un
troisième. Programmer, c'est aussi être organisé.
Documenter son code
Avant de terminer ce chapitre, je veux juste vous présenter un point qui peut sembler futile
(mais qui ne l'est pas). On vous l'a dit dès le début, il est important de mettre des
commentaires dans son programme pour comprendre ce qu'il fait.
C'est particulièrement vrai pour les fonctions puisque vous allez peut-être utiliser des
fonctions écrites par d'autres programmeurs. Il est donc important de savoir ce que font ces
fonctions sans avoir besoin de lire tout le code ! (Rappelez-vous, le programmeur est
fainéant… )
113
Comme il y a de la place dans les fichiers d'en-tête, on en profite généralement pour y décrire
ce que font les fonctions. On y fait généralement figurer trois choses :
#ifndef MATH_H_INCLUDED
#define MATH_H_INCLUDED
/*
*/
#endif // MATH_H_INCLUDED
Bien sûr, dans ce cas, le descriptif est très simple. Mais c'est une habitude qu'il faut prendre.
C'est d'ailleurs tellement courant de mettre des commentaires dans les fichiers.hqu'il existe des
systèmes quasi-automatiques qui génèrent des sites web ou des livres à partir de ces
commentaires.
/**
* \return nombreRecu + 2
*/
114
Pour l'instant, cela peut vous paraître un peu inutile mais vous verrez dans la partie III de ce
cours qu'avoir une bonne documentation est essentiel. À vous de choisir la notation que vous
préférez.
int total = 0;
total += secondes;
return total;
}
Cette fonction calcule un nombre de secondes en fonction d'un nombre d'heures, de minutes et
de secondes qu'on lui transmet. Rien de bien compliqué !
Pour bien voir comment on doit procéder, on va regarder le code complet. J'aimerais que vous
l'écriviez dans votre IDE pour faire les tests en même temps que moi :
#include <iostream>
115
using namespace std;
// Prototype de la fonction
// Main
int main()
return 0;
// Définition de la fonction
int total = 0;
total += secondes;
return total;
}
Ce code donne le résultat suivant :
116
4225
Sachant que 1 heure = 3600 secondes, 10 minutes = 600 secondes, 25 secondes =… 25
secondes, le résultat est logique car 3600 + 600 + 25 = 4225.
Maintenant, supposons que l'on veuille rendre certains paramètres facultatifs, par exemple
parce qu'on utilise en pratique plus souvent les heures que le reste.
On va devoir modifier le prototype de la fonction (et non sa définition, attention).
Indiquez la valeur par défaut que vous voulez donner aux paramètres s'ils ne sont pas
renseignés lors de l'appel à la fonction :
Voici le code complet que vous devriez avoir sous les yeux :
#include <iostream>
// Main
int main()
return 0;
117
// Définition de la fonction, SANS les valeurs par défaut
int total = 0;
total += secondes;
return total;
}
Si vous avez lu attentivement ce code, vous avez dû vous rendre compte de quelque chose
: les valeurs par défaut sont spécifiées uniquement dans le prototype, pas dans la définition de
la fonction ! Si votre code est découpé en plusieurs fichiers, alors il ne faut spécifier les
valeurs par défaut que dans le fichier d'en-tête.h. On se fait souvent avoir, je vous préviens…
Si vous vous trompez, le compilateur vous indiquera une erreur à la ligne de la définition de la
fonction.
Bon, ce code ne change pas beaucoup du précédent. À part les valeurs par défaut dans le
prototype, rien n'a été modifié (et le résultat à l'écran sera toujours le même).
La nouveauté maintenant, c'est qu'on peut supprimer des paramètres lors de l'appel de la
fonction (ici dans lemain()). On peut par exemple écrire :
4200
Tant que vous indiquez au moins les paramètres obligatoires, il n'y a pas de problème.
118
Bon, mine de rien il y a quand même quelques pièges, ce n'est pas si simple que cela !
On va voir ces pièges sous la forme de questions / réponses :
Et si je veux envoyer à la fonction juste les heures et les secondes, mais pas les minutes ?
Tel quel, c'est impossible. En effet, je vous l'ai dit plus haut, le compilateur analyse les
paramètres de gauche à droite. Le premier correspondra forcément aux heures, le second aux
minutes et le troisième aux secondes.
//OK
Est-ce que je peux rendre tous mes paramètres facultatifs ?
Oui, cela ne pose pas de problème :
Règles à retenir
En résumé, il y a 2 règles que vous devez retenir pour les valeurs par défaut :
•seul le prototype doit contenir les valeurs par défaut (pas la définition de la fonction) ;
• les valeurs par défaut doivent se trouver à la fin de la liste des paramètres (c'est-à-dire
à droite).
En résumé
• Une fonction est une portion de code contenant des instructions et ayant un rôle précis.
119
• Tous les programmes ont au moins une fonction :main(). C'est celle qui s'exécute au
démarrage du programme.
• Découper son programme en différentes fonctions ayant chacune un rôle différent
permet une meilleure organisation.
• Une même fonction peut être appelée plusieurs fois au cours de l'exécution d'un
programme.
• Une fonction peut recevoir des informations en entrée (appelées arguments) et
renvoyer un résultat en sortie grâce à return.
• Les fonctions peuvent recevoir des références en argument pour modifier directement
une information précise en mémoire.
• Lorsque le programme grossit, il est conseillé de créer plusieurs fichiers regroupant
des fonctions. Les fichiers .cppcontiennent les définitions des fonctions et les fichiers.h,
plus courts, contiennent leurs prototypes. Les fichiers .hpermettent d'annoncer
l'existence des fonctions à l'ensemble des autres fichiers du programme.
120
Manipulez les tableaux
Dans de très nombreux programmes, on a besoin d'avoir plusieurs variables du même type et
qui jouent quasiment le même rôle. Pensez par exemple à la liste des utilisateurs d'un site web
: cela représente une grande quantité de variables de type string. Ou les dix meilleurs scores de
votre jeu, que vous stockerez dans différentes cases mémoires, toutes de type int.
Le C++, comme presque tous les langages de programmation, propose un moyen simple de
regrouper des données identiques dans un seul paquet. Et comme l'indique le titre du chapitre,
on appelle ces regroupements de variables des tableaux.
Dans ce chapitre, je vais vous apprendre à manipuler deux sortes de tableaux. Ceux dont la
taille est connue à l'avance, comme pour la liste des dix meilleurs scores, et ceux dont la taille
peut varier en permanence, comme la liste des visiteurs d'un site web qui, généralement, ne
cesse de grandir.
Vous vous en doutez certainement, les tableaux dont la taille est fixée à l'avance sont plus
faciles à utiliser et c'est donc par eux que nous allons commencer.
Un exemple d'utilisation
Si vous voulez afficher la liste des 5 meilleurs scores des joueurs, il va vous falloir en réalité
deux listes : la liste des noms de joueurs et la liste des scores qu'ils ont obtenus. Nous allons
donc devoir déclarer 10 variables pour mettre toutes ces informations dans la mémoire de
l'ordinateur. On aura par exemple :
string nomMeilleurJoueur1("Nanoc");
string nomMeilleurJoueur2("M@teo21");
string nomMeilleurJoueur5("Archimede");
int meilleurScore1(118218);
int meilleurScore2(100432);
int meilleurScore3(87347);
int meilleurScore4(64523);
121
int meilleurScore5(31415);
Et pour afficher tout cela, il va aussi falloir pas mal de travail.
cout << "1) " << nomMeilleurJoueur1 << " " << meilleurScore1 << endl;
cout << "2) " << nomMeilleurJoueur2 << " " << meilleurScore2 << endl;
cout << "3) " << nomMeilleurJoueur3 << " " << meilleurScore3 << endl;
cout << "4) " << nomMeilleurJoueur4 << " " << meilleurScore4 << endl;
cout << "5) " << nomMeilleurJoueur5 << " " << meilleurScore5 << endl;
Cela fait énormément de lignes ! Imaginez maintenant que vous vouliez afficher les 100
meilleurs scores et pas seulement les 5 meilleurs. Ce serait terrible, il faudrait déclarer 200
variables et écrire 100 lignes quasiment identiques pour l'affichage ! Autant arrêter tout de
suite, c'est beaucoup trop de travail.
C'est là qu'interviennent les tableaux : nous allons pouvoir déclarer les 100 meilleurs scores et
les noms des 100 meilleurs joueurs d'un seul coup. On va créer une seule case dans la
mémoire qui aura de la place pour contenir les 100intqu'il nous faut et une deuxième pour
contenir les 100string. Magique non ?
Il faut quand même que les variables aient un lien entre elles pour que l'utilisation d'un tableau
soit justifiée. Mettre dans un même tableau l'âge de votre chien et le nombre d'internautes
connectés n'est pas correct. Même si ces deux variables sont desint.
Dans cet exemple, nous avons besoin de 100 variables, c'est-à-dire 100 places dans le tableau.
C'est ce qu'on appelle, en termes techniques, la taille du tableau. Si la taille du tableau reste
inchangée et est fixée dans le code source, alors on parle d'un tableau statique. Parfait ! C'est
ce dont nous avons besoin pour notre liste des 100 meilleurs scores.
On indique le type, puis le nom choisi et enfin, entre crochets, la taille du tableau. Voyons
cela avec un exemple :
#include <iostream>
int main()
122
{
return 0;
}
Voyons à quoi ressemble la mémoire avec un de nos schémas habituels :
La mémoire
de l'ordinateur après avoir déclaré deux tableaux
On retrouve les deux zones mémoires avec leurs étiquettes mais, cette fois, chaque zone est
découpée en cases : trois cases pour le tableau anglesTriangleet cinq cases pour le
tableau meilleurScore. Pour l'instant, aucune de ces cases n'est initialisée. Leur contenu est donc
quelconque.
123
Il est également possible de déclarer un tableau en utilisant comme taille une constante de
type intouunsigned int. On indique simplement le nom de la constante entre les crochets, à la
place du nombre.
double anglesIcosagone[tailleTableau];
Il faut impérativement utiliser une constante comme taille du tableau.
Je vous conseille de toujours utiliser des constantes pour exprimer les tailles de vos tableaux
plutôt que d'indiquer directement la taille entre les crochets. C'est une bonne habitude à
prendre.
Bon. Nous avons de la place dans la mémoire. Il ne nous reste plus qu'à l'utiliser.
meilleurScore[2] = 5;
En effet, 3−1=23−1=2 ; la troisième case possède donc le numéro 2. Si je veux remplir mon
tableau des meilleurs scores comme dans l'exemple initial, je peux donc écrire :
124
Le gros point fort des tableaux, c'est qu'on peut les parcourir en utilisant une boucle. On peut
ainsi effectuer une action sur chacune des cases d'un tableau, l'une après l'autre : par exemple
afficher le contenu des cases.
On connaît a priori le nombre de cases du tableau, on peut donc utiliser une boucle for. Nous
allons pouvoir utiliser la variable ide la boucle pour accéder au ième élément du tableau. C'est
fou, on dirait que c'est fait pour !
}
La variableiprend successivement les valeurs 0, 1, 2, 3 et 4, ce qui veut dire que les valeurs
demeilleursScores[0], puismeilleursScores[1], etc. sont envoyées danscout.
Il faut faire très attention, dans la boucle, à ne pas dépasser la taille du tableau, sous peine de
voir votre programme planter. La dernière case dans cet exemple a le
numéronombreMeilleursScoresmoins un. Les valeurs autorisées deisont tous les entiers entre 0
etnombreMeilleursScoresmoins un compris.
Vous allez voir, le couple tableau / boucleforva devenir votre nouveau meilleur ami. En tout
cas, je l'espère : c'est un outil très puissant.
Un petit exemple
Allez, je vous propose un petit exemple légèrement plus complexe. Nous allons utiliser le
C++ pour calculer la moyenne de vos notes de l'année. Je vous propose de mettre toutes vos
notes dans un tableau et d'utiliser une boucle forpour le calcul de la moyenne. Voyons donc
tout cela étape par étape.
125
La première étape consiste à déclarer un tableau pour stocker les notes. Comme ce sont des
nombres à virgule, il nous faut des double.
double notes[nombreNotes];
La deuxième étape consiste à remplir ce tableau avec vos notes. J'espère que vous savez
encore comment faire !
double notes[nombreNotes];
notes[0] = 12.5;
notes[3] = 12;
notes[4] = 14.5;
notes[5] = 15;
Je me répète, mais c'est important : la première case du tableau a le numéro 0, la deuxième le
numéro 1, et ainsi de suite.
Pour calculer la moyenne, il nous faut additionner toutes les notes puis diviser le résultat
obtenu par le nombre de notes. Nous connaissons déjà le nombre de notes, puisque nous
avons la constante nombreNotes. Il ne reste donc qu'à déclarer une variable pour contenir la
moyenne.
Le calcul de la somme s'effectue dans une boucle forqui parcourt toutes les cases du tableau.
double moyenne(0);
//En arrivant ici, la variable moyenne contient la somme des notes (79.5)
126
moyenne /= nombreNotes;
Avec une petite ligne pour l'affichage de la valeur, on obtient le résultat voulu : un
programme qui calcule la moyenne de vos notes.
#include <iostream>
int main()
double notes[nombreNotes];
notes[0] = 12.5;
notes[3] = 12;
notes[4] = 14.5;
notes[5] = 15;
double moyenne(0);
//En arrivant ici, la variable moyenne contient la somme des notes (79.5)
127
moyenne /= nombreNotes;
cout << "Votre moyenne est : " << moyenne << endl;
return 0;
}
Voyons ce que cela donne quand on l'exécute :
Votre moyenne est : 13.25
Et cela marche ! Mais vous n'en doutiez pas, bien sûr ?
La première restriction est qu'on ne peut pas écrire une fonction qui renvoie un tableau
statique. C'est impossible.
La deuxième restriction est qu'un tableau statique est toujours passé par référence. Et il n'y a
pas besoin d'utiliser l'esperluette (&) : c'est fait automatiquement. Cela veut dire que,
lorsqu'on passe un tableau à une fonction, cette dernière peut le modifier.
//…
}
Il ne faut rien mettre entre les crochets.
Mais ce n'est pas tout ! Très souvent, on veut parcourir le tableau, avec une boucle forpar
exemple. Il nous manque une information cruciale. Vous voyez laquelle ?
//…
128
}
Oui, je sais c'est ennuyeux. Mais il ne faut pas vous en prendre à moi, je n'ai pas créé le
langage.
Pour vous entraîner, je vous propose d'écrire une fonction moyenne()qui calcule la moyenne des
valeurs d'un tableau.
Voici ma version :
/*
*/
double moyenne(0);
moyenne /= tailleTableau;
return moyenne;
}
Assez parlé de ces tableaux. Passons à la suite.
129
La première différence se situe au tout début de votre programme. Il faut ajouter la
ligne#include <vector>pour utiliser ces tableaux.
À cause de cette ligne, on parle souvent devectorà la place de tableau dynamique. J'utiliserai
parfois ce terme dans la suite.
La deuxième grosse différence se situe dans la manière de déclarer un tableau. On utilise la
syntaxe présentée :
#include <iostream>
int main()
vector<int> tableau(5);
return 0;
}
Il faut ici remarquer trois choses :
1. le type n'est pas le premier mot de la ligne, contrairement aux autres variables ;
2. on utilise une notation bizarre avec un chevron ouvrant et un chevron fermant ;
3. on écrit la taille entre parenthèses et non entre crochets.
Cela veut dire que les choses ne ressemblent pas vraiment aux tableaux statiques. Cependant,
vous allez voir que, pour parcourir le tableau, le principe est similaire.
Mais avant cela, il y a deux astuces bien pratiques à savoir.
On peut directement remplir toutes les cases du tableau en ajoutant un deuxième argument
entre les parenthèses :
130
vector<double> tableau; //Crée un tableau de 0 nombre à virgule
Euh… À quoi sert un tableau vide ?
Rappelez-vous que ce sont des tableaux dont la taille peut varier. On peut donc ajouter des
cases par la suite. Attendez un peu et vous saurez tout.
Changez la taille
Entrons maintenant dans le vif du sujet : faire varier la taille d'un tableau. Commençons par
ajouter des cases à la fin d'un tableau.
Il faut utiliser la fonction push_back(). On écrit le nom du tableau, suivi d'un point et du
mot push_backavec, entre parenthèses, la valeur qui va remplir la nouvelle case.
tableau.push_back(8);
131
Effet d'un push_back
sur un vector
Une case supplémentaire a été ajoutée au bout du tableau, de manière automatique. C'est fou
ce que cela peut être intelligent un ordinateur parfois.
Et bien sûr on peut ajouter beaucoup de cases à la suite les unes des autres.
132
Attention tout de même à ne pas trop supprimer de cases ! Un tableau ne peut pas contenir
moins de 0 éléments.
Je crois que je n'ai pas besoin d'en dire plus sur ce sujet.
Il nous reste quand même un petit problème à régler. Comme la taille peut changer, on ne sait
pas de manière certaine combien d'éléments contient un tableau. Heureusement, il y a une
fonction pour cela :size(). Avectableau.size(), on récupère un entier correspondant au nombre
d'éléments detableau.
//La taille peut varier mais la valeur de cette variable ne changera pas
#include <iostream>
int main()
notes.push_back(19.5);
notes.push_back(6);
133
notes.push_back(12);
notes.push_back(14.5);
notes.push_back(15);
double moyenne(0);
moyenne /= notes.size();
cout << "Votre moyenne est : " << moyenne << endl;
return 0;
}
On a écrit deux programmes qui font exactement la même chose de deux manières différentes.
C'est très courant, il y a presque toujours plusieurs manières de faire les choses. Chacun
choisit celle qu'il préfère.
134
void fonction(vector<int> a)
//…
}
Simple non ? Mais on peut quand même faire mieux. Je vous ai parlé, au chapitre précédent,
du passage par référence constante pour optimiser la copie. En effet, si le tableau contient
beaucoup d'éléments, le copier prendra du temps. Il vaut donc mieux utiliser cette astuce, ce
qui donne :
//…
}
Dans ce cas, le tableau dynamique ne peut pas être modifié. Pour changer le contenu du
tableau, il faut utiliser un passage par référence tout simple (sans leconstdonc).
Pour appeler une fonction recevant un vector en argument, il n'y a rien de particulier à faire.
Comme dans le cas des variables du chapitre précédent, il suffit de mettre le nom du tableau
dynamique comme paramètre entre les parenthèses lors de l'appel. Ce qui donne:
#ifndef TABLEAU_H_INCLUDED
#define TABLEAU_H_INCLUDED
#include <vector>
135
#endif // TABLEAU_H_INCLUDED
Il est évidemment possible d'écrire une fonction renvoyant un vector. Je suis sûr que vous
avez déjà deviné comment déclarer une telle fonction. Par exemple pour une fonction qui
renvoie un tableau multi-dimensionnels de nombres à virgule, on écrira:
vector<double> encoreUneFonction(int a)
//...
}
Il faut, cependant, noter que ceci va implicitement générer une copie du tableau quand la
fonction se termine. Pour éviter cela, on préfère utiliser un passage du tableau par référence,
comme nous l'avons vu dans le chapitre précédent. Les copies inutiles de tableaux sont des
sources courantes de ralentissement des programmes. Si vous avez besoin d'un programme
très performant, faites attention à vos tableaux.
Je vous vois d'ici froncer les sourcils et vous demander à quoi cela peut bien servir. Une fois
n'est pas coutume, je vous propose de commencer par visualiser la mémoire (figure suivante).
Vous verrez peut-être l'intérêt de ce concept pour le moins bizarre.
136
Un tableau bi-
dimensionnel dans la mémoire de l'ordinateur
La grosse case jaune représente, comme à chaque fois, une variable. Cette fois, c'est un
tableau de 5 éléments dont j'ai représenté les cases en utilisant des lignes épaisses. À
l'intérieur de chacune des cases, on trouve un petit tableau de 4 éléments dont on ne connaît
pas la valeur.
Mais, si vous regardez attentivement les points d'interrogation, vous pouvez voir une grille
régulière ! Un tableau de tableau est donc une grille de variables. Et là, je pense que vous
trouvez cela tout de suite moins bizarre.
On parle parfois de tableaux multi-dimensionnels plutôt que de grilles. C'est pour souligner
le fait que les variables sont arrangées selon des axes X et Y et pas uniquement selon un seul
axe.
Déclaration d'un tableau multi-dimensionnel
Pour déclarer un tel tableau, il faut indiquer les dimensions les unes après les autres entre
crochets :
type nomTableau[tailleX][tailleY]
Donc pour reproduire le tableau du schéma, on doit déclarer le tableau suivant :
int tableau[5][4];
Ou encore mieux, en déclarant des constantes :
137
int tableau[tailleX][tailleY];
Et c'est tout ! C'est bien le C++, non ?
double grilleExtreme[5][4][6][2][7];
Mais là, il ne faudra pas me demander un dessin. Je vous rassure quand même, il est rare de
devoir utiliser des grilles à plus de 3 dimensions. Ou alors, c'est que vous prévoyez de faire
des programmes vraiment compliqués. Les grilles à 3D sont quand même assez courantes,
pour des simulateurs 3D (avion, snowspeeder, etc. ;-) et pour tout ce qui touche à la physique
: représentation de l'espace, d'une vitesse, d'une accélération, d'une force, d'un tenseur, etc.
Notez qu'il est aussi possible de créer des tableaux multi-dimensionnels de taille variable en
utilisant les vectors. Pour une grille 2D d'entiers, on devra écrire :
grille.push_back(vector<int>(3,4)); //On ajoute une ligne de 3 cases contenant chacune le nombre 4 à notre grille
Chaque ligne peut donc avoir une longueur différente. On peut accéder à une ligne en utilisant
les crochets:
138
des tableaux multi-dimensionnels statiques à moins que le fait de pouvoir changer la taille de
la grille en cours de route soit un élément essentiel.
Les strings comme tableaux
Avant de terminer ce chapitre, il faut quand même que je vous fasse une petite révélation. Les
chaînes de caractères sont en fait des tableaux !
On ne le voit pas lors de la déclaration, c'est bien caché. Mais il s'agit en fait d'un tableau de
lettres. Il y a même beaucoup de points communs avec lesvector.
#include <iostream>
#include <string>
int main()
string nomUtilisateur("Julien");
cout << "Vous etes " << nomUtilisateur << "." <<endl;
cout << "Ah non, vous etes " << nomUtilisateur << "!" << endl;
return 0;
}
Testons pour voir :
Vous etes Julien.
Ah non, vous etes Lucien!
139
C'est fort ! Mais on peut faire encore mieux…
Les fonctions
On peut également utiliser size()pour connaître le nombre de lettres et push_back()pour ajouter
des lettres à la fin. La encore, c'est comme avec vector.
string texte("Portez ce whisky au vieux juge blond qui fume."); //46 caractères
cout << "Cette phrase contient " << texte.size() << " lettres." << endl;
Mais contrairement aux tableaux, on peut ajouter plusieurs lettres d'un coup. Et on utilise
le +=.
#include <iostream>
#include <string>
int main()
string prenom("Albert");
string nom("Einstein");
cout << "Vous vous appelez " << total << "." << endl;
return 0;
}
Cela donne bien sûr :
140
Vous vous appelez Albert Einstein.
C'est fou ce que c'est bien le C++ parfois !
En résumé
• Les tableaux sont des successions de variables en mémoire. Un tableau à 4 cases
correspond donc en mémoire à 4 variables les unes à la suite des autres.
• Un tableau s'initialise comme ceci :int meilleurScore[4];(pour 4 cases).
• La première case est toujours numérotée 0 (meilleurScore[0]).
• Si la taille du tableau est susceptible de varier, créez un tableau dynamique de
type vector:vector<int> tableau(5);.
• On peut créer des tableaux multi-dimensionnels. Par exemple, int tableau[5][4];revient à
créer un tableau de 5 lignes et 4 colonnes.
• Les chaînes de caractères stringpeuvent être considérées comme des tableaux. Chacune
des cases correspond à un caractère.
141
Lisez et modifiez des fichiers
Pour l'instant, les programmes que nous avons écrits étaient encore relativement
simples. C'est normal, vous débutez. Mais avec un peu d'entraînement, vous seriez
capables de créer de vraies applications. Vous commencez à connaître les bases du
C++ mais il vous manque quand même un élément essentiel : l'interaction avec des
fichiers.
Jusqu'à maintenant, vous avez appris à écrire dans la console et à récupérer ce que
l'utilisateur avait saisi. Vous serez certainement d'accord avec moi, ce n'est pas
suffisant. Pensez à des logiciels comme le bloc-note, votre IDE ou encore un tableur
: ce sont tous des programmes qui savent lire des fichiers et écrire dedans. Et même
dans le monde des jeux vidéo, on a besoin de cela : il y a bien sûr les fichiers de
sauvegardes, mais aussi les images d'un jeu, les cinématiques, les musiques, etc.
En somme, un programme qui ne sait pas interagir avec des fichiers risque d'être
très limité.
Voyons donc comment faire ! Vous verrez : si vous maîtrisez l'utilisation de cinet
decout, alors vous savez déjà presque tout.
On parle de flux pour désigner les moyens de communication d'un programme avec
l'extérieur. Dans ce chapitre, nous allons donc parler des flux vers les fichiers. Mais
dites simplement « lire et modifier des fichiers » quand vous n'êtes pas dans une
soirée de programmeurs.
L'en-têtefstream
Comme d'habitude en C++, quand on a besoin d'une fonctionnalité, il faut
commencer par inclure le bon fichier d'en-tête. Pour les fichiers, il faut
spécifier#include <fstream>en-haut de notre code source.
Vous connaissez déjà iostreamqui contient les outils nécessaires aux entrées/sorties
vers la console. iostreamsignifie en réalité input/output stream, ce qui veut dire « flux
d'entrées/sorties » en français. fstreamcorrespond à file stream, « flux vers les
fichiers » en bon français.
La principale différence est qu'il faut un flux par fichier. Voyons comment créer un
flux sortant, c'est-à-dire un flux permettant d'écrire dans un fichier.
142
cela comme de grosses variables améliorées. Ces objets contiennent beaucoup
d'informations sur les fichiers ouverts et proposent des fonctionnalités comme fermer
le fichier, retourner au début et bien d'autres encore.
L'important pour nous est que l'on déclare un flux exactement de la même manière
qu'une variable, une variable dont le type serait ofstreamet dont la valeur serait le
chemin d'accès du fichier à lire.
Comme pour les variables, il y a quelques règles à suivre pour le choix du nom du
flux :
#include <iostream>
#include <fstream>
int main()
ofstream monFlux("C:/Nanoc/scores.txt");
// C:/Nanoc/scores.txt
return 0;
}
J'ai indiqué entre guillemets le chemin d'accès au fichier. Ce chemin doit prendre
l'une ou l'autre des deux formes suivantes :
143
• Un chemin relatif, c'est-à-dire montrant l'emplacement du fichier depuis
l'endroit où se situe le programme sur le disque. Par exemple
:Fichiers/scores.txtsi mon programme se situe dans le
dossierC:/Nanoc/C++/.
À partir de là, on peut utiliser le flux pour écrire dans le fichier.
ofstream monFlux(nomFichier.c_str());
else
}
Tout est donc prêt pour l'écriture. Et vous allez voir que ce n'est pas vraiment
nouveau.
144
Je vous avais dit que tout était comme pourcout. C'est donc sans surprise que je
vous présente le moyen d'envoyer des informations dans un flux : ce sont les
chevrons (<<) qu'il faut utiliser.
#include <iostream>
#include <fstream>
#include <string>
int main()
ofstream monFlux(nomFichier.c_str());
if(monFlux)
monFlux << "Bonjour, je suis une phrase écrite dans un fichier." << endl;
int age(23);
monFlux << "J'ai " << age << " ans." << endl;
else
return 0;
145
}
Si j'exécute ce programme, je retrouve ensuite sur mon disque un
fichierscores.txtdont le contenu est présenté en figure suivante.
Pour pouvoir écrire à la fin d'un fichier, il faut le spécifier lors de l'ouverture en
ajoutant un deuxième paramètre à la création du flux :ofstream
monFlux(nomFichier.c_str(), ios::app);.
appest un raccourci pour append, le verbe anglais qui signifie « ajouter à la fin ».
Avec cela, plus de problème d'écrasement des données : tout ce qui sera écrit sera
ajouté à la fin.
Lisez un fichier
Nous avons appris à écrire dans un fichier, voyons maintenant comment fonctionne
la lecture d'un fichier. Vous allez voir, ce n'est pas très différent de ce que vous
connaissez déjà.
146
if(monFlux)
else
}
Rien de bien nouveau.
… et le lire
Il y a trois manières différentes de lire un fichier :
string ligne;
double nombre;
string mot;
147
Cette méthode lit ce qui se trouve entre l'endroit où l'on se situe dans le fichier et
l'espace suivant. Ce qui est lu est alors traduit endouble,intoustringselon le type de
variable dans lequel on écrit.
char a;
monFlux.get(a);
Ce code lit une seule lettre et la stocke dans la variablea.
Cette méthode lit réellement tous les caractères. Les espaces, retours à la ligne et
tabulations sont, entre autres, lus par cette fonction. Bien que bizarres, ces
caractères seront néanmoins stockés dans la variable.
Souvenez-vous de ce que nous avions vu au chapitre 5 lorsque nous avons
découvert l'utilisation decin. Nous avions appris qu'il fallait
utilisercin.ignore()lorsque l'on passait de la lecture mot par mot à la lecture ligne
par ligne. Il en va de même ici. Il faudra donc écrire:
ifstream monFlux("C:/Nanoc/C++/data.txt");
string mot;
string ligne;
Pour savoir si l'on peut continuer à lire, il faut utiliser la valeur renvoyée par la
fonctiongetline(). En effet, en plus de lire une ligne, cette fonction renvoie
unboolindiquant si l'on peut continuer à lire. Si la fonction renvoietrue, tout va bien,
148
la lecture peut continuer. Si elle renvoiefalse, c'est qu'on est arrivé à la fin du fichier
ou qu'il y a eu une erreur. Dans les deux cas, il faut s'arrêter de lire.
Vous vous rappelez des boucles ? On cherche à lire le fichier tant qu'on n'a pas
atteint la fin. La bouclewhileest donc le meilleur choix. Voici comment faire :
#include <iostream>
#include <fstream>
#include <string>
int main()
ifstream fichier("C:/Nanoc/fichier.txt");
if(fichier)
149
}
else
return 0;
}
Une fois que l'on a lu les lignes, on peut les manipuler facilement. Ici, je me contente
d'afficher les lignes mais, dans un programme réel on les utiliserait autrement. La
seule limite est votre imagination.
C'est la méthode la plus utilisée pour lire un fichier. Une fois que l'on a récupéré les
lignes dans une variablestring, on peut facilement travailler dessus grâce aux
fonctions utilisables sur les chaînes de caractères.
Quelques astuces
Il ne reste que quelques astuces à voir et vous saurez alors tout ce qu'il faut sur les
fichiers.
void f()
//Utilisation du fichier
150
Il arrive par contre qu'on ait besoin de fermer le fichier avant sa fermeture
automatique. Il faut alors utiliser la fonctionclose()des flux.
void f()
//Utilisation du fichier
}
De la même manière, il est possible de retarder l'ouverture d'un fichier après la
déclaration du flux en utilisant la fonctionopen().
void f()
//Utilisation du fichier
}
Comme vous le voyez, c'est très simple. Toutefois, dans la majorité des cas, c'est
inutile. Ouvrir directement le fichier et le laisser se fermer automatiquement suffit.
151
Certaines personnes aiment utiliseropen()etclose(), alors que ce n'est pas
nécessaire. On peut ainsi mieux voir où le fichier est ouvert et où il est refermé. C'est
une question de goût, à vous de voir ce que vous préférez.
Le curseur dans le fichier
Plongeons un petit peu plus dans les détails techniques et voyons comment se
déroule la lecture. Quand on ouvre un fichier dans le bloc-note, par exemple, il y a un
curseur qui indique l'endroit où l'on va écrire. Dans la figure suivante, le curseur se
situe après les deux « s » sur la quatrième ligne.
Position du curseur
Si l'on tape sur une touche du clavier, une lettre sera ajoutée à cet endroit du fichier.
J'imagine que je ne vous apprends rien en disant cela. Ce qui est plus intéressant,
c'est qu'en C++ il y a aussi, en quelque sorte, un curseur.
ifstream fichier("C:/Nanoc/scores.txt")
le fichierC:/Nanoc/scores.txtest ouvert et le curseur est placé tout au début du
fichier. Si on lit le premier mot du fichier, on obtient bien sûr la chaîne de caractères «
Nanoc » puisque c'est le premier mot du fichier. Ce faisant, le « curseur C++ » se
déplace jusqu'au début du mot suivant, comme à la figure suivante.
Le mot suivant qui peut être lu est donc « : », puis « 118218 », et ainsi de suite
jusqu'à la fin. On est donc obligé de lire un fichier dans l'ordre. Ce n'est pas très
pratique.
152
La première chose à faire est de savoir où se situe le curseur. Dans un deuxième
temps, on pourra le déplacer.
Connaître sa position
Il existe une fonction permettant de savoir à quel octet du fichier on se trouve.
Autrement dit, elle permet de savoir à quel caractère du fichier on se situe.
Malheureusement, cette fonction n'a pas le même nom pour les flux entrant et
sortant et, en plus, ce sont des noms bizarres. Je vous ai mis les noms des deux
fonctions dans un petit tableau
Pourifstream Pourofstream
tellg() tellp()
ofstream fichier("C:/Nanoc/data.txt");
cout << "Nous nous situons au " << position << "eme caractere du fichier." << endl;
Se déplacer
Là encore, il existe deux fonctions, une pour chaque type de flux.
Pourifstream Pourofstream
seekg() seekp()
Elles s'utilisent de la même manière, je ne vous présente donc qu'une des deux
versions.
Ces fonctions reçoivent deux arguments : une position dans le fichier et un nombre
de caractères à ajouter à cette position :
flux.seekp(nombreCaracteres, position);
Les trois positions possibles sont :
153
Voilà donc notre problème de lecture résolu.
#include <iostream>
#include <fstream>
int main()
int taille;
taille = fichier.tellg();
cout << "Taille du fichier : " << taille << " octets." << endl;
return 0;
}
Je suis sûr que vous le saviez !
Voilà, on a fait le tour des notions principales. Vous êtes prêts à vous lancer seuls
dans le vaste monde des fichiers.
En résumé
154
• En C++, pour lire ou écrire dans un fichier, on doit inclure le fichier d'en-
tête<fstream>.
• On doit créer un objet de typeofstreampour ouvrir un fichier en écriture
etifstreampour l'ouvrir en lecture.
• L'écriture se fait comme aveccout:monFlux << "Texte";tandis que la lecture
se fait comme aveccin:monFlux >> variable;.
• On peut lire un fichier ligne par ligne avecgetline().
• Le curseur indique à quelle position vous êtes au sein du fichier, pendant une
opération de lecture ou d'écriture. Au besoin, il est possible de déplacer ce
curseur.
155
TP : le mot mystère
Depuis le début de ce cours sur le C++, vous avez découvert de nombreuses notions
: le compilateur, l'IDE, les variables, les fonctions, les conditions, les boucles… Vous
avez pu voir des exemples d'utilisation de ces notions au fur et à mesure mais est-ce
que vous avez pris le temps de créer un vrai programme pour vous entraîner ? Non ?
Eh bien c'est le moment de s'y mettre !
On trouve régulièrement des TP au milieu des cours du Site du Zéro. Celui-ci ne fait
pas exception. Le but ? Vous forcer à vous lancer « pour de vrai » dans la
programmation !
Le sujet de ce TP n'est pas très compliqué mais promet d'être amusant : nous allons
mélanger les lettres d'un mot et demander à un joueur de retrouver le mot « mystère
» qui se cache derrière ces lettres (figure suivante).
Préparatifs et conseils
Le jeu que nous voulons réaliser consiste à retrouver un mot dont les lettres ont été
mélangées. C'est simple en apparence mais il va nous falloir utiliser des notions que
nous avons découvertes dans les chapitres précédents :
• les variablesstring;
• les fonctions ;
• les structures de contrôle (boucles, conditions… ).
N'hésitez pas à relire rapidement ces chapitres pour bien être dans le bain avant de
commencer ce TP !
156
Quel est ce mot ? MSERETY
MYRESTE
Ce n'est pas le mot !
Mais moi, je n'ai pas envie que vous vous perdiez ! Je vais donc vous donner une
série de conseils pour que vous soyez préparés au mieux. Bien entendu, ce sont
juste des conseils, vous en faites ce que vous voulez.
1. L'étape 1 est très simple : l'utilisateur doit saisir un mot qu'on va stocker en
mémoire (dans une variable de typestring, car c'est le type adapté). Si vous
connaissezcoutetcin, vous ne mettrez pas plus de quelques minutes à écrire
le code correspondant.
2. L'étape 2 est la plus complexe : vous avez unstringqui contient un mot
comme « MYSTERE » et vous voulez aléatoirement mélanger les lettres pour
obtenir quelque chose comme « MSERETY ». Comment faire ? Je vais vous
aider un peu pour cela car vous devez utiliser certaines choses que nous
n'avons pas vues.
157
3. L'étape 3 est de difficulté moyenne : vous devez créer une boucle qui
demande de saisir un mot et qui le compare au mot mystère. La boucle
s'arrête dès que le mot saisi est identique au mot mystère.
Créez un canevas de code avec les étapes
Comme vous le savez, tous les programmes contiennent une fonction main(). Écrivez
dès maintenant des commentaires pour séparer les principales étapes du
programme. Cela devrait donner quelque chose de comparable au squelette ci-
dessous :
int main()
return 0;
}
À vous de réaliser les étapes ! Pour y aller en difficulté croissante, je vous conseille
de faire d'abord l'étape 1, puis l'étape 3 et enfin l'étape 2.
Lorsque vous aurez réalisé les étapes 1 et 3, le programme vous demandera un mot
et vous devrez le ressaisir. Ce ne sera pas très amusant mais, de cette manière,
vous pourrez valider les premières étapes ! N'hésitez donc pas à y aller pas à pas !
158
Bravo !
Comme vous le voyez, le programme ne propose pas encore le mot avec les lettres
mélangées, mais si vous arrivez déjà à faire cela, vous avez fait 50% du travail !
#include <iostream>
int main()
int nbAleatoire(0);
srand(time(0));
nbAleatoire = rand() % 5;
159
return 0;
}
Tirer une lettre au hasard
Tirer un nombre au hasard c'est bien mais, pour ce programme, j'ai besoin de tirer
une lettre au hasard pour mélanger les lettres !
Imaginons que vous ayez unstringappelémotMysterequi contient le mot « MYSTERE
». Vous avez appris que lesstringpouvaient être considérés comme des tableaux,
souvenez-vous ! Ainsi,motMystere[0]correspond à la première lettre,motMystere[1]à
la deuxième lettre, etc.
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>
int main()
string motMystere("MYSTERE");
srand(time(0));
160
cout << "Lettre au hasard :" << motMystere[position];
return 0;
}
Retirez une lettre d'unstring
Pour éviter de tirer 2 fois la même lettre d'un mot, je vous conseille de retirer au fur et
à mesure les lettres qui ont été piochées. Pour ce faire, on va faire appel
àerase()sur le mot mystère, comme ceci :
motMelange = melangerLettres(motMystere);
On lui envoie lemotMystere, elle nous renvoie unmotMelange.
Correction
C'est l'heure de la correction !
Vous avez sûrement passé du temps à réfléchir à ce programme. Cela n'a peut-être
pas toujours été facile et vous n'avez pas forcément su tout faire. Ce n'est pas grave
! Ce qui compte, c'est d'avoir essayé : c'est comme cela que vous progressez le plus
!
Normalement, les étapes 1 et 3 étaient assez faciles pour tout le monde. Seule
l'étape 2 (mélange des lettres) demandait plus de réflexion : je l'ai isolée dans une
fonctionmelangerLettrescomme je vous l'ai suggéré plus tôt.
Le code
Sans plus attendre, voici la correction :
#include <iostream>
161
#include <string>
#include <ctime>
#include <cstdlib>
string melange;
int position(0);
while (mot.size() != 0)
melange += mot[position];
mot.erase(position, 1);
162
return melange;
int main()
srand(time(0));
motMelange = melangerLettres(motMystere);
do
cout << endl << "Quel est ce mot ? " << motMelange << endl;
if (motUtilisateur == motMystere)
163
{
else
return 0;
}
Ne vous laissez pas surprendre par la « taille » du code (qui n'est d'ailleurs pas très
gros) et soyez méthodiques en le lisant : commencez par lire lemain()et non la
fonctionmelangerLettres(). Regardez les différentes étapes du programme une par
une : isolées, elles sont plus simples à comprendre.
Des explications
Voici quelques explications pour mieux comprendre le programme, étape par étape.
while (mot.size() != 0)
164
position = rand() % mot.size();
melange += mot[position];
mot.erase(position, 1);
}
À chaque passage de boucle, on tire un nombre au hasard compris entre 0 et le
nombre de lettres qu'il reste dans le mot. On ajoute ces lettres piochées
aléatoirement dans unstringmelangeet on retire les lettres du mot d'origine pour ne
pas les piocher une deuxième fois.
}while (motUtilisateur != motMystere); //On recommence tant qu'il n'a pas trouvé
On affiche un message différent selon qu'on a trouvé ou non le mot mystère. Le
programme s'arrête dès qu'on sort de la boucle, donc dès qu'on a trouvé le mot
mystère.
Téléchargement
Vous pouvez télécharger le code source du programme grâce au lien suivant :
165
•
o Ajoutez des sauts de ligne au début : lorsque le premier joueur saisit
le mot mystère la première fois, vous devriez créer plusieurs sauts de
lignes pour que le joueur 2 ne voie pas le mot qui a été saisi, sinon
c'est trop facile pour lui.
Utilisez plusieursendl, par exemple, pour créer plusieurs retours à la ligne.
•
Proposez au joueur de faire une nouvelle partie. Actuellement, une
o
fois le mot trouvé, le programme s'arrête. Et si vous demandiez «
Voulez-vous faire une autre partie ? (o/n) ». En fonction de la réponse
saisie, vous reprenez au début du programme. Pour ce faire, il faudra
créer une grosse boucledo… whilequi englobe les 3 étapes du
programme.
o Fixez un nombre maximal de coups pour trouver le mot mystère.
Vous pouvez par exemple indiquer « Il vous reste 5 essais » et lorsque
les 5 essais sont écoulés, le programme s'arrête en affichant la
solution.
o Calculez le score moyen du joueur à la fin du programme : après
plusieurs parties du joueur, affichez-lui son score, qui sera la moyenne
des parties précédentes. Vous pouvez calculer le nombre de points
comme vous le voulez.
Vous devrez sûrement utiliser les tableaux dynamiquesvectorpour stocker les scores
de chaque partie au fur et à mesure, avant d'en faire la moyenne.
MYSTERE
XYLOPHONE
ABEILLE
PLUTON
MAGIQUE
AVERTISSEMENT
Au lieu de demander le mot à deviner (étape 1) on va chercher dans un fichier
comme celui-ci un mot aléatoire. À vous d'utiliser les fonctionnalités de lecture de
fichiers que vous avez apprises ! … Allez, puisque vous m'êtes sympathiques, je
vous propose même de télécharger un fichier-dictionnaire tout prêt avec des dizaines
de milliers de mots ! Merci qui ?! Télécharger le fichier
Si vous avez d'autres idées, n'hésitez pas à compléter encore ce programme ! Cela
vous fera beaucoup progresser, vous verrez. Haut du formulaire
166
Déclarez les pointeurs
:Nous voilà dans le dernier chapitre de présentation des bases du C++. Accrochez-
vous car le niveau monte d'un cran !
Le sujet des pointeurs fait peur à beaucoup de monde et c'est certainement un des
chapitres les plus complexes de ce cours. Une fois cet écueil passé, beaucoup de
choses vous paraîtront plus simples et plus claires.
Les pointeurs sont utilisés dans tous les programmes C++, même si vous n'en avez
pas eu conscience jusque là. Il y en a partout. Pour l'instant, ils étaient cachés et
vous n'avez pas eu à en manipuler directement. Cela va changer avec ce chapitre.
Nous allons apprendre à gérer très finement ce qui se passe dans la mémoire de
l'ordinateur.
C'est un chapitre plutôt difficile, il est donc normal que vous ne compreniez pas tout
du premier coup. N'ayez pas peur de le relire une seconde fois dans quelques jours
pour vous assurer que vous avez bien tout assimilé !
Je vous avais dit que, lorsque l'on déclare une variable, l'ordinateur nous « prête »
une place dans sa mémoire et y accroche une étiquette portant le nom de la variable.
int main()
int ageUtilisateur(16);
return 0;
}
On pouvait donc représenter la mémoire utilisée dans ce programme comme sur le
schéma :
167
La mémoire
lorsque l'on déclare une variable
168
Le vrai visage de
la mémoire : beaucoup de cases, toutes numérotées
Sur le schéma, on voit cette fois toutes les cases de la mémoire avec leurs adresses.
Notre programme utilise une seule de ces cases, la 53768, pour y stocker sa
variable.
L'adresse est donc un deuxième moyen d'accéder à une variable. On peut atteindre
la case jaune du schéma par deux chemins différents :
• On peut passer par son nom (l'étiquette) comme on sait déjà le faire…
• Mais on peut aussi accéder à la variable grâce à son adresse (son numéro de
case). On pourrait alors dire à l'ordinateur « Affiche moi le contenu de
l'adresse 53768 » ou encore « Additionne les contenus des adresses 1267 et
91238 ».
Est-ce que cela vous tente d'essayer ? Vous vous demandez peut-être à quoi cela
peut bien servir. Utiliser l'étiquette était un moyen simple et efficace, c'est vrai. Mais
nous verrons plus loin que passer par les adresses est parfois nécessaire.
Affichez l'adresse
169
En C++, le symbole pour obtenir l'adresse d'une variable est l'esperluette (&). Si je
veux afficher l'adresse de la variableageUtilisateur, je dois donc
écrire&ageUtilisateur. Essayons.
#include <iostream>
int main()
int ageUtilisateur(16);
return 0;
}
Chez moi, j'obtiens le résultat suivant :
L'adresse est : 0x22ff1c
Vous aurez certainement un résultat différent. La case peut changer d'une exécution
à l'autre du programme.
Même si elle contient des lettres, cette adresse est un nombre. Celui-ci est
simplement écrit en hexadécimal (en base 16, si vous voulez tout savoir), une autre
façon d'écrire les nombres. Les ordinateurs aiment bien travailler dans cette base.
Pour information, en base 10 (notre écriture courante), cette adresse correspond à 2
293 532. Cependant, ce n'est pas une information très intéressante.
Ce qui est sûr, c'est qu'afficher une adresse est très rarement utile. Souvenez-vous
simplement de la notation. L'esperluette veut dire « adresse de ». Donccout <<
&a;se traduit en français par « Affiche l'adresse de la variable a ».
On a déjà utilisé l'esperluette dans ce cours pour tout autre chose : lors de la
déclaration d'une référence. C'est le même symbole qui est utilisé pour deux choses
différentes. Attention à ne pas vous tromper !
Voyons maintenant ce que l'on peut faire avec ces adresses.
Les pointeurs
Les adresses sont des nombres. Vous connaissez plusieurs types permettant de
stocker des nombres :int,unsigned int,double. Peut-on donc stocker une adresse
dans une variable ?
170
La réponse est « oui ». C'est possible, mais pas avec les types que vous connaissez.
Il nous faut utiliser un type un peu particulier : le pointeur.
Un pointeur est une variable qui contient l'adresse d'une autre variable.
Retenez bien cette phrase. Elle peut vous sauver la vie dans les moments les plus
difficiles de ce chapitre.
Déclarez un pointeur
Pour déclarer un pointeur il faut, comme pour les variables, deux choses :
• un type ;
• un nom.
Pour le nom, il n'y a rien de particulier à signaler. Les mêmes règles que pour les
variables s'appliquent. Ouf !
Le type d'un pointeur a une petite subtilité. Il faut indiquer quel est le type de variable
dont on veut stocker l'adresse et ajouter une étoile (*). Je crois qu'un exemple sera
plus simple.
int *pointeur;
Ce code déclare un pointeur qui peut contenir l'adresse d'une variable de type int.
double *pointeurA;
//Un pointeur qui peut contenir l'adresse d'un nombre entier positif
string *pointeurC;
vector<int> *pointeurD;
171
//Un pointeur qui peut contenir l'adresse d'un tableau dynamique de nombres entiers
//Un pointeur qui peut contenir l'adresse d'un nombre entier constant
Pour le moment, ces pointeurs ne contiennent aucune adresse connue. C'est une
situation très dangereuse. Si vous essayez d'utiliser le pointeur, vous ne savez pas
quelle case de la mémoire vous manipulez. Ce peut être n'importe quelle case, par
exemple celle qui contient votre mot de passe Windows ou celle stockant l'heure
actuelle. J'imagine que vous vous rendez compte des conséquences que peut avoir
une mauvaise manipulation des pointeurs. Il ne faut donc jamaisdéclarer un pointeur
sans lui donner d'adresse.
Par conséquent, pour être tranquille, il faut toujours déclarer un pointeur en lui
donnant la valeur 0 :
int *pointeur(0);
double *pointeurA(0);
string *pointeurC(0);
vector<int> *pointeurD(0);
Je me répète, mais c'est très important : déclarez toujours vos pointeurs en les
initialisant à l'adresse 0.
Stockez une adresse
Maintenant qu'on a la variable, il n'y a plus qu'à y mettre une valeur. Vous savez déjà
comment obtenir l'adresse d'une variable (rappelez-vous du&). Allons-y !
int main()
int ageUtilisateur(16);
int *ptr(0);
172
//Un pointeur pouvant contenir l'adresse d'un nombre entier
ptr = &ageUtilisateur;
return 0;
}
La ligneptr = &ageUtilisateur;est celle qui nous intéresse. Elle écrit l'adresse de la
variableageUtilisateurdans le pointeurptr. On dit alors que le pointeurptrpointe
surageUtilisateur.
La mémoire après
la déclaration d'une variable et d'un pointeur pointant sur cette variable
173
On retrouve quelques éléments familiers : la mémoire avec sa grille de cases et la
variableageUtilisateurdans la case n°53768.
La nouveauté est bien sûr le pointeur. Dans la case mémoire n°14566, il y a une
variable nomméeptrqui a pour valeur l'adresse 53768, c'est-à-dire l'adresse de la
variableageUtilisateur.
Voilà, vous savez tout ou presque. Cela peut sembler absurde pour le moment («
Pourquoi stocker l'adresse d'une variable dans une autre case ? ») mais faites-moi
confiance : les choses vont progressivement s'éclairer pour vous.
Si vous avez compris le schéma précédent, alors vous pouvez vous attaquer aux
programmes les plus complexes.
Affichez l'adresse
Comme pour toutes les variables, on peut afficher le contenu d'un pointeur.
#include <iostream>
int main()
int ageUtilisateur(16);
int *ptr(0);
ptr = &ageUtilisateur;
cout << "L'adresse de 'ageUtilisateur' est : " << &ageUtilisateur << endl;
cout << "La valeur de pointeur est : " << ptr << endl;
return 0;
}
Cela donne :
L'adresse de 'ageUtilisateur' est : 0x2ff18
La valeur de pointeur est : 0x2ff18
174
La valeur du pointeur est donc bien l'adresse de la variable pointée. On a bien réussi
à stocker une adresse !
int main()
int ageUtilisateur(16);
int *ptr(0);
ptr= &ageUtilisateur;
cout << "La valeur est : " << *ptr << endl;
return 0;
}
En faisantcout << *ptr, le programme effectue les étapes suivantes :
Récapitulatif de la notation
175
Je suis d'accord avec vous, la notation est compliquée. L'étoile a deux significations
différentes et on utilise l'esperluette alors qu'elle sert déjà pour les références… Ce
n'est pas ma faute mais il va falloir faire avec. Essayons donc de récapituler le tout.
L'allocation dynamique
Vous vouliez savoir à quoi servent les pointeurs ? Vous êtes sûrs ? Bon, alors je
vous montrer une première utilisation.
176
Pour demander manuellement une case dans la mémoire, il faut utiliser
l'opérateurnew.
newdemande une case à l'ordinateur et renvoie un pointeur pointant vers cette case.
int *pointeur(0);
La mémoire après
l'allocation dynamique d'un entier
Si vous changez la valeur du pointeur, vous perdez le seul moyen d'accéder à cette
case mémoire. Vous ne pourrez donc plus l'utiliser ni la supprimer ! Elle sera
définitivement perdue mais elle continuera à prendre de la place. C'est ce qu'on
appelle une fuite de mémoire.
Il faut donc faire très attention !
Une fois allouée manuellement, la variable s'utilise comme n'importe quelle autre. On
doit juste se rappeler qu'il faut y accéder par le pointeur, en le déréférençant.
int *pointeur(0);
177
pointeur = new int;
La mémoire après
avoir alloué une variable et changé la valeur de cette variable
À part son accès un peu spécial (via*pointeur), nous avons donc une variable en
tout point semblable à une autre.
Il nous faut maintenant rendre la mémoire que l'ordinateur nous a gentiment prêtée.
Libérez la mémoire
Une fois que l'on n'a plus besoin de la case mémoire, il faut la rendre à l'ordinateur.
Cela se fait vial'opérateurdelete.
int *pointeur(0);
178
L'image est très parlante. Si l'on suit la flèche, on arrive sur une case qui ne nous
appartient pas. Il faut donc impérativement empêcher cela. Imaginez que cette case
soit soudainement utilisée par un autre programme ! Vous risqueriez de modifier les
variables de cet autre programme.
Après avoir fait appel àdelete, il est donc essentiel de supprimer cette « flèche » en
mettant le pointeur à l'adresse 0. Ne pas le faire est une cause très courante de
plantage des programmes.
int *pointeur(0);
#include <iostream>
179
int main()
int* pointeur(0);
cout << "Vous avez " << *pointeur << " ans." << endl;
return 0;
}
Ce programme est plus compliqué que sa version sans allocation dynamique, c'est
vrai ! Mais on a le contrôle complet sur l'allocation et la libération de la mémoire.
Dans la plupart des cas, ce n'est pas utile de le faire. Mais vous verrez plus tard que,
pour faire des fenêtres, la bibliothèque Qt utilise beaucoup newetdelete. On peut ainsi
maîtriser précisément quand une fenêtre est ouverte et quand on la referme, par
exemple.
180
• partager une variable dans plusieurs morceaux du code ;
• sélectionner une valeur parmi plusieurs options.
Si vous n'êtes dans aucun de ces trois cas, c'est très certainement que vous n'avez
pas besoin des pointeurs.
Vous connaissez déjà le premier de ces trois cas. Concentrons nous sur les deux
autres.
Vous avez déjà joué à un jeu de stratégie ? Prenons un exemple tiré d'un jeu de ce
genre. Voici une image issue du fameux Warcraft III (figure suivante).
Programmer un tel jeu est bien sûr très compliqué mais on peut quand même
réfléchir à certains des mécanismes utilisés. Sur l'image, on voit des humains (en
rouge) attaquer des orcs (en bleu). Chaque personnage a une cible précise. Par
181
exemple, le fusilier au milieu de l'écran semble tirer sur le gros personnage bleu qui
tient une hache.
Nous verrons dans la suite de ce cours comment créer des objets, c'est-à-dire des
variables plus évoluées (par exemple une variable de type « personnage », de type «
orc » ou encore de type « bâtiment »). Bref, chaque élément du jeu pourra être
modélisé en C++ par un objet.
Le pointeur est donc réellement utilisé ici comme une flèche reliant un personnage à
son ennemi.
Nous verrons par la suite comment écrire ce type de code ; je crois même que créer
un mini-RPG (un mini jeu de rôle, si vous préférez) sera le thème principal des
chapitres de la partie II. Mais chut, c'est pour plus tard.
#include <iostream>
#include <string>
int main()
182
reponseA = "La peur des jeux de loterie";
cout << "Qu'est-ce que la 'kenophobie' ? " << endl; //On pose la question
cout << "A) " << reponseA << endl; //Et on affiche les trois propositions
char reponse;
switch(reponse)
case 'A':
break;
case 'B':
reponseUtilisateur = &reponseB;
break;
case 'C':
reponseUtilisateur = &reponseC;
183
break;
cout << "Vous avez choisi la reponse : " << *reponseUtilisateur << endl;
return 0;
}
Une fois que le pointeur a été déplacé (dans leswitch), on peut l'utiliser comme
moyen d'accès à la réponse de l'utilisateur. On a ainsi un moyen d'atteindre
directement cette variable sans devoir refaire le test à chaque fois qu'on en a
besoin.
C'est une variable qui contient une valeur que l'on ne pouvait pas connaître avant
(puisqu'elle dépend de ce que l'utilisateur a entré).
C'est certainement le cas d'utilisation le plus rare des trois mais il arrive parfois qu'on
soit dans cette situation. Il sera alors temps de vous rappeler les pointeurs !
En résumé
• Chaque variable est stockée en mémoire à une adresse différente.
• Il ne peut y avoir qu'une seule variable par adresse.
• On peut récupérer l'adresse d'une variable avec le symbole&, comme ceci
:&variable.
• Un pointeur est une variable qui stocke l'adresse d'une autre variable.
• Un pointeur se déclare comme ceci :int *pointeur;(dans le cas d'un pointeur
vers une variable de typeint).
• Par défaut, un pointeur affiche l'adresse qu'il contient. En revanche, si on
écrit*pointeur, on obtient la valeur qui se trouve à l'adresse indiquée par le
pointeur.
• On peut réserver manuellement une case en mémoire avecnew. Dans ce cas,
il faut libérer l'espace en mémoire dès qu'on n'en a plus besoin, avecdelete.
• Les pointeurs sont une notion complexe à saisir du premier coup. N'hésitez
pas à relire ce chapitre plusieurs fois. Vous comprendrez mieux leur intérêt
plus loin dans cet ouvrage.
184