Unicaen/Cours de Cpp

Ceci est un cours destiné au personnes qui ignore presque tout de l'informatique, c'est-à-dire celles qui savent juste qu'il y a un bouton Démarrer en bas à gauche de l'écran dans Windows, et au minimum qui connaissent la notion de fichier et de répertoire. Si vous avez des questions, n'hésitez pas à les poser sur la page de discussion (en haut juste à droite de article). Si vous trouvez ce document d'une utilité quelconque (ou pas), dites le (sur la page de discussion). En bref, exprimez vous, quoi !!!

En général, les exercices sont surtout là pour attirer l'attention sur des détails qui peuvent prendre toute leur importance lors de la suppression des bugs dans un programme. Ainsi, vous ne pourrez pas dire que vous ne saviez pas !

Installation de Dev-C++
Pour programmer en Maple, vous avez besoin de... Maple. Pour programmer en Scheme, il vous faut DrScheme. Et bien pour programmer en C++, il vous faut télécharger le logiciel DevC++, qui est gratuit, et qui est là : http://prdownloads.sourceforge.net/dev-cpp/devcpp4.zip. Cliquez sur Download, puis enregistrez ça n'importe où vous voulez, puis clique droit&rarr;Extraire tout..., puis Suivant, Suivant, Terminer. Une fenêtre devrait surgir. Double-cliquez sur Setup.exe. Dans la nouvelle fenêtre qui surgit (encore), cliquez sur Yes puis Next. Attendez un peu. Cochez la case Yes, Launch the program file puis cliquez sur Finish. Le programme démarre. Cliquez sur Ok puis encore Ok. Voila, Dev-C++ est installé. C'était facile, non ? Fermez toutes les fenêtres, sauf Dev-C++, pour vous débarasser de tous ces écrans désormais inutiles.

Une fois installé, Dev-C++ est accessible à partir de deux endroits : sauf sur les comptes maths_applis de la fac où le raccourci est aussi accessible à partir du menu Démarrer, mais ailleurs.
 * Démarrer&rarr;Dev-C++&rarr;Dev-C++
 * C:\Dev-C++\DevCpp.exe dans l'explorateur Windows (les fenêtre dans lesqulles ont voit les fichiers et les dossiers).

Leçon 1 : Premier programme
Il est grand temps de commencer à programmer en C++ pour de vrai. Dans Dev-C++, cliquez sur File dans la barre de menus (en haut), puis cliquez sur New source file. Une sous-fenêtre avec quelque ligne de codes surgit. Faîtes Ctrl+A puis touche Suppr (ou Del, suivant les cas) pour effacer tout ça. Maintenant, recopiez ceci intégralement : main { cout<<"Bravo, vous venez de faire votre premier programme !!!"<
 * 2) include 

Dans DrScheme, une fois le code tapez, il faut faire Run pour exécuter le code. Eh bien en C++, c'est, en première approximation, pareil. Dans le menu Execute, cliquez sur Compile and Run. Il va vous demandez de donner un nom au fichier source que vous venez d'éditer. Tapez premier_programme, puis Entrée.

Deux fenêtre surgissent alors. Celle qui a un fond noir, c'est votre programme. Appuyez sur une touche pour quitter, conformément à ce qui est inscrit sur l'écran. Il reste une petite boîte de dialogue qui porte comme nom Compilation completed. Vous pouvez entre autres y lire : Total errors : 0. Appuyez sur Continuer. Vous revenez alors à l'éditeur, et pouvez donc faire des modifications à votre programme avant de le (re)tester en (re)cliquant sur Execute&rarr;Compile and Run.

Ces étapes entre la création et l'exécution d'un programme sont à connaître absolument par coeur. Ainsi, les leçons suivantes ne se focaliseront que sur le contenu du code source, sauf exceptions.

Qu'avez vous (ou lui) fait ?
Vous avez suivi toutes les étapes de la création d'un programme en C++, qui se déroule en trois étapes : Ce système peut paraître de prime abord assez lourd, mais c'est cela qui fait ça puissance. Il faut cependant déjà pas mal de pratique pour l'entrevoir.
 * 1) Création du fichier source premier_programme.cpp, qui contient le code source du programme.
 * 2) Compilation du programme en un fichier executable premier_programme.exe.
 * 3) Execution de ce fichier par la machine.

Lors de cette mystérieuse phase qu'est la compilation, le compilateur lit votre fichier de haut en bas. Dès qu'il vois une ligne qui commence par #include, il cherche le fichier indiqué dans la machine, le lit de haut en bas, puis revient à votre fichier à l'endroit d'où il est parti, et continue de même jusqu'à la fin. A chaque fois qu'il voit un mot qu'il ne "connaît" pas, il regarde s'il à déjà rencontré au-dessus, sinon il renvoie un message d'erreur très explicite.

Exercices

 * Verifier que vous avez bien le fichier premier_programme.exe sur le disque dur. En fait, il s'agit simplement de vérifier que lors de l'enregistrement, vous savez où vous mettez vos fichiers et savez les retrouver au besoin.
 * Remplacer le texte affiché par "Vous êtes un maître". Vous devriez voir un bug. Tant pis. C'est pourquoi il faut éviter d'utiliser les caractères accentués dans un programme. Le mieux est encore d'utiliser l'anglais. En fait, je dirais même mieux : n'utilisez en aucun cas les caractères accentués dans vos programmes.
 * Supprimer la ligne system("PAUSE");. Lors de l'exécution, vous devriez voir la fenêtre apparaître très furtivement. C'est le programme qui s'arrête sans vous demander votre avis.
 * Essayer d'afficher le résultat du produit de 97 par 523. Idem avec 10/3, 10.0/3.0, 10.0/3 et 10/3.0 . Il est peut-être encore trop tôt pour une explication précise du phénomène. Retenez seulement que si vous avez un bug dans votre programme, ceci peut en être la cause.
 * Indice : il ne faut pas utiliser les guillemets.


 * Tentez de localisez les deux fichiers iostream.h et stdlib.h utilisés, et jetez un coup d'oeil dedans. Oui, effectivement, vous n'êtes manifestement pas encore en mesure de comprendre ces glyphes. Patience donc...
 * ''Indice : ils sont quelques part dans le répertoire C:\Dev-C++\Include

Leçon 2 : les nombres
Aujourd'hui, nous allons parler de nombres. Nous allons voir comment manipuler des nombres en C++, mais surtout, et c'est peut-être là qu'est la difficulté, ce qu'est un nombre au sens de l'informatique.

En mathématiques et dans la vie de tous les jours, un nombre est juste quelque chose qui représente une quantité. Il peut être aussi grand que l'on veut, où aussi proche de 0 qu'on le veut. Il peut donc posséder une quantité inimaginable de chiffres, et également une quantité inimaginable de décimales. Eh bien en informatique, l'ensemble des nombres n'est pas infini, pour la bonne raison que pour stocker tout les chiffres d'un nombre infiniment grand, il faudrait une quantité infinie de mémoire. Peut-être est il bon de savoir à ce niveau là ce qu'est la mémoire, car de nos jours, les nombres utilisés pour quantifier la mémoire d'un système sont presque du domaine de l'abstrait...

La mémoire en informatique
Attention, cette section est peut-être assez abstraite. (Faudrait faire un sondage).

La base de l'unité de mémoire d'un ordinateur est le bit, qui peut être soit 0, soit 1, ou bien soit blanc, soit noir, ou bien soit pile soit face. En gros, il peut être soit ceci, soit cela, mais surtout pas autre chose.

Supposons que l'on dispose d'un seul bit, ou bien d'une seule pièce de monnaie. Comme celle-ci peut-être soit pile, soit face, notre système peut-être dans deux états distincts. On peut donc stocké les nombres 0 et 1, mais rien d'autre. (ou toute information "isomorphe", il suffit d'établir une correspondance). Maintenant, supposons que l'on travaille avec 8 bits, (= 1 octet). Nous pouvons dès lors stocker 28 "informations", par exemple, les nombre de 0 à 255. Cela est encore très limité. On a souvent besoin de nombres plus grands que 255.

En C++, en ce qui concerne les nombres au sens le plus large du terme, ils sont stockés sur 8 octets, soit 64 bits. On peut dès lors utiliser les nombres de 0 à 18446744073709551616 (.1844674407*1020), ce qui ne correspond en fait qu'à e44 à peu près. En d'autres termes, n'espérez pas calculer e45 en C++, il vous renverra une magnifique erreur.

Mais ce n'est pas fini ! Jusqu'à présent, on a travaillé qu'avec des entiers naturels. Pour passer aux entiers relatifs, il intervient la notion de signe, qui est binaire (+ ou -) et donc qui divise le nombre de possibilités par 2. A cela s'ajoute les nombres réels, qui ont une virgule, et qui nécessite donc une manière de stocker l'emplacement du symbole décimal. A cela s'ajoute le fait que pour contourner ces limites, les C++iens ont utilisé le fait que dans les grands nombres, les dernière chiffres sont "signifiant" et sont donc purement et simplement supprimés.

Ainsi, en C++, les quantités numériques doivent être traitées avec beaucoup de précautions, et c'est peu dire.

Et concrètement, ça donne quoi ?
Outre la notion de nombre, cette section introduit également la notion de variable, la notion de type de donnée, et l'instruction d'affectation. Voici le programme de base : main { double a=1.0; cout<
 * 2) include 

Que fait ce programme ? A cette question, il faudrait répondre, pour être assez précis : ce programme définit la variable a</tt> comme étant de type double, puis affecte à cette variable la valeur 1.0. Il affiche ensuite la valeur de cette variable a à l'écran, grâce à une mystérieuse syntaxe...

La notion de variable
Pour manipuler les données dans un programme, il est en général nécessaire de définir des variables, en leur donnant un nom au choix. Les variables doivent être vues comme des boîtes toutes identiques, sur lesquelles sont collées des étiquettes portant mention de leur nom, et contenant la valeur qui lui à été affectée.

Contrairement au programme étudié ici, les variables sont en général là pour être modifiées au cours de l'exécution du programme. Ainsi, une même variable vue à deux endroits différents dans le programme peut contenir deux valeurs distinctes.

La notion de type de donnée
J'ai chez moi une boîte d'allumette. Vous me demander de venir avec une boîte pour me donner quelque chose (et le seul moyen de transport possible à ce moment là sera cette boîte, car un PC est con ;-). Manque de bol, vous vouliez y mettre une BD. C'est votre faute, il fallait me dire de quel type de boîte vous aviez besoin. Et bien en C++, c'est tout pareil. Ici, pour le moment, nous stockons nos nombres dans des boîtes de type double</tt>, mais il existe pleins d'autres types de boîtes, plus ou moins adaptée. Une partie de l'art du programmeur est de choisir le bon type de boîte.

L'instruction d'affectation
&Ccedil;a sert à rien d'acheter des boîtes si c'est pour ne rien mettre dedans !

Il y a une petite différence assez subtile entre le symbole '=' en mathématique et le symbole '=' en C++ (qui est d'ailleurs ':=' sur Maple) :
 * En mathématiques, lorsque l'on écrit 'x=y', cela signifie que x=y 'et' y=x, et ce n'est pas sensé changer.
 * En C++, si on écrit 'x=y', cela signifie que l'on recopie la valeur de la variable y dans la variable x (et je dis "dans", pour rappeler l'analogie des boîtes). Plus tard, si la valeur de la variable 'y' change, il n'y a aucune raison pour que celle de 'x' change.

Au passage, vous vous demandez peut-être pourquoi il est écrit '1.0' et non pas '1' tout court. Il paraît que ça a une influence, vous l'avez vu dans les exercices précédents. Il est donc de bon ton de toujours rajouter ce '.0'. Cela restera obligatoire jusqu'à nouvel ordre.

Utilisation des variables
Une fois qu'on a bien gentiment déclaré notre variable, il faut s'en servir. Encore faut il que ce soit dans le bon contexte. Si je vous demande de me donner le produit vectoriel de 5 par 3, vous allez me dire : "impossible". Et bien en C++, c'est pareil. Dans notre programme, on ne s'en sert que au moment de l'affichage sur l'écran. Il n'y a pas beaucoup d'autres endroits où l'on peut s'en servir. Tant pis.

Opérations sur les nombres
Ceci est plutôt un sous chapitre pour rien. Car avec des variables de type double, on ne peut qu'utiliser les quatres opérations : la somme '+', la soustraction '-', le produit '*' et la division '/'.

La syntaxe est la suivante : en supposant que nous ayons défini deux variables de types double et qu'elles ont été initialisées, la somme s'écrira a+b</tt>, la différence a-b</tt>, le produit a*b</tt> et la division a/b</tt> si b&ne;0. Ce genre d'expression peut apparaître n'importe où une variable de type double est acceptée.

Exercices
Solution : main { double a=2.0; double b=9.5; double c=a+b; b=b+a; a=a+c; a=a+2*a; b=a+c; cout<<a<<endl; cout<<b<<endl; cout<<c<<endl; system("PAUSE"); }
 * Souvent, dans un soucis d'organisation, on déclare toutes les variables du programme au début du programme, avant de les affecter plus tard. Une instruction telle que double a;</tt> est donc tolérée. Supprimez l'affectation de la valeur 1.0 à la variable 'a' dans le programme d'étude. Qu'advient-t-il ?
 * Donnez une valeur de départ de votre choix à 'a', puis affichez à l'écran a+1, a*4, a*a, a/a
 * Mettez 'a' à 0, et demandez l'affichage de 5.0/0.0, 5.0/a, a/0.0, a/a. Curieux, non ? Observez vous les warnings en bas de l'écran ?
 * Intervertissez les deux premières lignes. Que ce passe-t-il ? Les erreurs sont affichées en bas de l'écran.
 * Définissez deux nombres 'a' et 'b' de valeurs respective 2.0 et 9.5, puis définissez 'c' comme la somme de ces deux nombres. Puis ajoutez 'a' à 'b', puis 'c' à 'a', puis '2*a' à 'a', puis la somme de 'a' et 'c' à b. Pouvez vous prévoir les valeurs respectives de 'a', 'b' et 'c' à la fin du programme ?

Leçon 3 : avec des 'si'
Un programme devient intéressant à partir du moment où il est capable lui-même de prendre des décisions en fonction des données qu'il "connaît" au moment de la prise de décision. Le programme d'illustration affiche à l'écran si un nombre donné est positif, négatif ou nul. Cela permet par ailleurs d'introduire trois des principaux comparateur. main { double a=-3.0; if(a>0) { cout<<"Le nombre donne est positif"<<endl; } else if(a<0) { cout<<"Le nombre donne est negatif"<<endl; } else if(a==0) { cout<<"Le nombre donne est nul"<<endl; } else { cout<<"Y'a eu un probleme, la"<<endl; } system("PAUSE"); }

Comme vous pouvez le constater, la syntaxe global d'une instruction de test est : if(test) {actions} [else if(test) {action}] ... [else {action}] Les crochets '[]' signifient que qu'ils contiennent est facultatif. Vous n'êtes pas obligés d'utiliser ces instruction si vous en avez pas besoin. Les points de suspension '...' signifient que vous pouvez utilisez autant de fois la construction qui les précède que vous le désirez.

Notez également la gestion des erreurs : normalement, le nombre est soit positif, soit négatif, soit nul, néanmoins on est jamais trop sûr de quel bug pourrait se produire...

Chaque 'if' correspond à un test. Si un test est vrai, le test suivant n'est pas effectué, sinon, le programme passe au test suivant. Si tous les test échouent, la partie contenue par le 'else' final est effectuée. 'else' signifie "sinon".

Pour comparer des nombres, C++ fournit au moins 5 opérateurs : Notez le double signe '=='. Il faut être très vigilant, car si on oublie un '=', le programme marche quand même, parfois... sauf qu'il bug, bien évidemment.
 * '<' : Execute les actions correspondantes si le nombre de droite est strictement inférieur au nombre de gauche.
 * '>' : Renvoi vrai si le nombre de droite est strictement supérieur au nombre de gauche
 * '==' : Retourne vrai si les deux nombres de part et d'autres sont égaux.
 * '>=' : Supérieur ou égal. Moyen mnémotechnique : ça se lit et ça se prononce dans le même ordre.
 * '<=' : Inférieur ou égal.

Notez également que je n'est pas utilisé de caractères accentués. JAMAIS de tels caractères dans un programme. Ils n'EXISTENT pas.

Exercices

 * Remplacer a>0</tt> par a>=0</tt> dans le programme d'exemple. Que se passe-t-il si a=5 ? Si a=0 ?
 * Remplacer a>0</tt> par 0 puis 0.5, puis 1.0, puis 5.0, puis -4.0. Qu'advient-t-il ?
 * Remplacer a>0</tt> par a. Que se passe-t-il si a=0.0 ? Si a=1.0 ?
 * Remplacer a>0</tt> par a=0</tt>, puis a=4</tt>, tt>0=a</tt>, 0==a</tt>. Dans chacun des cas, essayer avec a=0.0, puis a=1.0, et afficher 'a' à la fin du programme (dans les cas qui marchent). Dans les cas qui ne marche pas, essayez de voir pourquoi. Souvenez vous que '=' est une instruction d'affectation.
 * Rajouter un test a>=0</tt> après le dernier test, qui devra afficher un message différent. Essayer le programme avec a=1.0, a=0.0 puis a=-1.0. Avez vous vu votre message ? Maintenant, supprimer bêtement les mots 'else', ainsi que le dernier 'else {...}' intégralement. Ré-essayez le programme avec a=1.0, a=0.0 et a=-1.0. Dans quels cas voyez vous votre message ?

Ces exercices doivent finir par vous paraître triviaux, sans quoi la chasse au bugs risque de s'avérer plus que difficile.

Avec le temps : les boucles while
Jusqu'à présent, tous les programmes étudiés été tout-à-fait "linéaire", c'est-à-dire que chaque instuction écrite n'était exécutée qu'une seule fois. La notion de temps intervenait déjà un peu, mais en gros, si une ligne était écrite au-dessous d'une autre, alors elle s'exécutait après (la ligne du dessus).

Nous allons maintenant voir la notion de boucle, c'est-à-dire des instructions qui sont affichée une seule fois, mais exécutée plusieurs fois. Le programme minimal possible est le suivant, qui affiche les nombres de 1.0 à 10.0 : main { double a=0.0; while(a<10.0) { a=a+1.0; cout<<a<<endl; }  system("PAUSE"); } Le synopsis correspondant est : while(test) {actions} Et cela doit se lire : tant que le test est vrai, on exécute les actions.

La ligne la plus intéressante est la ligne 4 (<tt>a=a+1.0;</tt>). En effet, à cet enplacement, on ajoute 1.0 à 'a'. Mais que vaut 'a' ? Et bien ça dépend. Au tout début, il vaut 0.0, puis une fois qu'on lui a ajouté 1.0, il vaut 1.0. Après on arrive à la fin de la boucle. On sort de la boucle si et seulement si a>10.0. Ce n'est manifestement le cas, donc on recommence : on ajoute 1.0 à 'a' qui vaut à ce moment précis 1.0, ce qui fait que 'a' passe à 2.0. Au bout d'un moment, on arrive à a=9.0. On ajoute 1.0, donc 'a' passe à '10.0'. Puis on affiche 'a', et enfin on refait encore une fois le test : a<10 ? Non. On sort donc de la boucle, c'est-à-dire qu'on passe à l'instruction <tt>system("PAUSE");</tt>. Voila pour les bases.

Utilisations
En général, on utilise le concept de compteur dans les boucles. C'est-à-dire qu'on utilise au moins deux variables, dont une qui est seulement là pour varier d'une certaine quantité à une autre. Pour illustrer, nous allons faire un programme qui calcule la somme des nombres de '5.0' à '90.0', en partant de 90, pourquoi pas ? main{ double sum=0.0; double i=90.0; while(i>5.0) { sum=sum+i; i=i-1; } cout<<sum<<endl; system("PAUSE"); } L'idée ici est que l'on utilise une variable "auxiliaire", le compteur, modifier n fois la variable 'principale', celle qui nous intéresse au final, en fonction de la valeur courante du compteur.

Nous avons ici la première utilité "réelle" des variables "invisibles", c'est-à-dire que l'utilisateur qui exécute le programme ne voit jamais aucune trace de l'existence de ces variables. Dans tous les logiciels que vous utilisez, sans aucune exceptions, se cachent derrière la scène des milliers de variables.

La technique exposée ici est énormément utilisant en programmation. Elle doit donc vous venir à l'esprit comme par réflexe. Des exemples d'utilisation simples : le calcul de la puissance d'un nombre, de la factorielle, des séries entières...

Exercices

 * Dans le premier programme de cette leçon, intervertir les deux lignes de la boucle while. Quels changements observez vous ? Changer le test et la valeur initiale de 'a' pour rétablir l'affichage des nombres de 1 à 10.
 * Déplacer l'instruction <tt>system("PAUSE")</tt> à l'intérieur de la boucle.
 * Supprimer la ligne d'incrémentation (a=a+1.0) et remplacer le 'a' dans <tt>cout<<a<<endl;</tt> par <tt>(a=a+1.0)</tt>. Qu'en déduisez vous ? Note : ce genre de chose doit tout de même être évité. Si vous ne comprenez pas ce qui se passe à cet endroit là, attendez d'avoir vu la notion de fonction. Pour ce qui le "supportent", voila la réponse : l'instruction d'affectation retourne la valeur affectée.