Série 1 :
Remise en route, Makefiles.

Buts

Cette série vise trois buts :
  1. vous remettre en tête la programmation de base ;
  2. vous permettre une toute première pratique des Makefiles (plus dans la projet !) ;
  3. lire l'introduction au projet.

N'oubliez pas non plus de vous inscrire (et commencez à naviguer) sur le MOOC correspondant : https://www.coursera.org/learn/programmation-orientee-objet-cpp/ .

Préliminaires :

Avant de commencer les exercices décrits dans cette série, créez le répertoire ~/Desktop/myfiles/cpp/serie14  (c.-à-d. créez le sous-répertoire serie14  dans le répertoire ~/Desktop/myfiles/cpp ; j'ai mis « 14 » pour faire suite au premier semestre si vous utilisez le même endroit).

Travaillez dans ce répertoire.

Je vous rappelle également que ces exercices ont des niveaux :

En général, la totalité de la série n'est pas prévue pour être finie en 2 heures ! La série est à considérer comme un regroupement de plusieurs exercices, un peu comme un chapitre de livre d'exercices, où chacun peut choisir (à l'aide des indications ci-dessus) ce qui lui semble adapté à sa progression.

Le niveau moyen pour 2 heures d'exercice correspond à deux exercices niveau 1 et un exercice niveau 2.

Pour finir, je vous conseille également, en plus des 2 heures d'exercices à l'emploi du temps, de travailler par vous-même chez vous, typiquement sur votre projet. Ce travail supplémentaire devrait en moyenne correspondre à 3 heures hebdomadaires pour un étudiant de niveau moyen.

La nouveauté de ce second semestre est l'introduction du projet et de certains exercices spécifiques dédiées à la progression du projet.


Exercice 1 : arithmétique rationnelle (remise en jambes, niveau 1)

Exercice n°40 (page 95 et 276) de l'ouvrage C++ par la pratique.

Le but de cet exercice, destiné à vous « remettre en jambes », est de coder les bases de l'arithmétique des nombres rationnels. C'est la copie de l'exercice 1 de la dernière série du premier semestre (si vous ne l'avez pas fait....)

Un autre but, moins direct, est que cet exercice pourrait (libre à vous) vous servir de base pour pratiquer les concepts de la Programmation Orientée Objet que nous allons voir pendant le semestre : faites évoluer votre solution chaque semaine avec les nouveaux concepts présentés.

Un nombre rationnel est défini par deux entiers p et q, tels que :

  1. q > 0
  2. p et q sont premiers entre eux.
p représente le numérateur et q le dénominateur

Par exemple : 1/2 : p=1, q=2 ; -3/5 : p=-3, q=5 ; 2 : p=2, q=1.

Quelle type de données utiliser pour représenter les nombres rationnels ?

Écrivez un programme rationnels.cc, contenant cette structure de donnée et une fonction affiche() permettant d'afficher un tel rationnel.

Testez votre programme avec les 3 rationnels donnés en exemple ci-dessus. Le programme devra afficher :

1/2
-3/5
2

On veut maintenant implémenter les 4 opérations élémentaires :

l'addition
Rationnel addition(Rationnel r1, Rationnel r2);
définie par
p1/q1 + p2/q2 = reduction(p1*q2+p2*q1/(q1*q2))
reduction(p/q) trouve les nombres p0 et q0 tels que p0/q0 = p/q et p0 et q0 vérifient la définition donnée plus haut (en particulier sont premier entre eux)

Pour la fonction reduction(), on utilisera le calcul de PGDC implémenté dans l'exercice 6 de la série 5 du premier semestre

Exemples :

1/2 + -3/5 = -1/10
2 + -3/5 = 7/5
2 + 2 = 4

Remarque : toute sophistication de la formule ci-dessus (en particulier si q1 = q2) peut évidemment être implémentée pour la fonction addition().

la soustraction
Rationnel soustraction(Rationnel r1, Rationnel r2);
définie par
p1/q1 - p2/q2 = reduction(p1*q2-p2*q1/(q1*q2))

Exemples :

1/2 - -3/5 = 11/10
2 - -3/5 = 13/5
-3/5 - -3/5 = 0
la multiplication
Rationnel multiplication(Rationnel r1, Rationnel r2);
définie par
p1/q1 * p2/q2 = reduction(p1*p2/(q1*q2))

Exemples :

1/2 * -3/5 = -3/10
2 * -3/5 = -6/5
-3/5 * -3/5 = 9/25
la division
Rationnel division(Rationnel r1, Rationnel r2);
définie par
p1/q1 / (p2/q2) = reduction(p1*q2/(q1*p2))
si p2 > 0, par
p1/q1 / (p2/q2) = reduction((-p1)*q2/(q1*(-p2)))
si p2 < 0 et non définie si p2 = 0.

Exemples :

1/2 / (-3/5) = -5/6
2 / (-3/5) = -10/3
-3/5 / (-3/5) = 1

Exercice 2 : factorielles revisitées (compilation séparée, Makefile, niveau 1)

Le but de cet exercice facultatif est de vous faire pratiquer la compilation séparée.

[ Si nécessaire, pour une présentation complémentaire à celle du cours des concepts de base de la compilation séparée, consultez le début de la mini-référence sur les 'Makefiles' et revenez ici lorsque cette mini-référence vous y renvoit. ]

On va pour cela reprendre l'exercice 2 de la série 6 du premier semestre (si vous ne l'avez pas fait, c'est l'occasion !), mais au lieu de définir toutes les fonctions (demander_nombre(), factorielleIterative() et factorielleRecursive()) dans un même fichier, nous allons créer 4 fichiers sources :

  1. factmain.cc qui sera le corps du programme principal ;
  2. factorielleIterative.cc qui définira une fonction
    int factorielle(int n)
    implémentant l'algorithme itératif du calcul des factorielles ;
  3. factorielleRecursive.cc qui définira aussi une fonction
    int factorielle(int n)
    mais implémentant la version récursive ;
  4. et demander_nombre.cc qui définira la fonction du même nom.

Ces fichiers sources vont nous permettre de créer deux programmes : factorielleIterative qui utilisera la version itérative, et factorielleRecursive qui utilisera la version récursive de l'algorithme.

Séparez votre programme factorielle.cc de l'exercice 2 de la série 6 du premier semestre en ces quatre fichiers et renommez les fonctions factorielleIterative() et factorielleRecursive() simplement factorielle() (oui, le même nom pour les deux).

Modifiez le corps de main (dans factmain.cc) de sorte à n'avoir qu'un seul appel à la fonction factorielle().

Essayez de compiler factmain.cc : ça ne joue pas car il manque à ce fichier les prototypes des fonctions demander_nombre(),et factorielle().

Il faut pour cela inclure les fichiers "entête" (.h) correspondants.

Créez le fichier demander_nombre.h contenant le prototype de la fonction demander_nombre(), puis ajoutez

#include "demander_nombre.h"
au début de factmain.cc.

Créez ensuite le fichier factorielle.h contenant le prototype de la fonction factorielle() (les deux fonctions implémentées ont bien le même prototype, seul l'algorithme change, mais ce n'est justement pas le « problème » du fichier .h qui, lui, n'a qu'un seul prototype à fournir). Puis ajoutez l'inclusion de ce fichier dans factmain.cc.

Il faut encore inclure les définitions et prototypes nécessaires à la compilation des trois autres fichiers :

Il ne nous reste plus qu'à « compiler » (compiler et faire l'édition de liens de) nos programmes :

g++ -c -o demander_nombre.o demander_nombre.cc
g++ -c -o factorielleRecursive.o factorielleRecursive.cc
g++ -c -o factorielleIterative.o factorielleIterative.cc
g++ -c -o factmain.o factmain.cc

g++ factmain.o factorielleRecursive.o demander_nombre.o -o factorielleRecursive
g++ factmain.o factorielleIterative.o demander_nombre.o -o factorielleIterative

Cela étant fastidieux, on va maintenant chercher à écrire un Makefile qui effectue toutes ces étapes pour nous.
[ Pour une présentation plus détaillée de l'outil make et du fonctionnement des Makefile, consultez la mini-référence 'Makefiles'. ]

Note: comme évoqué à la fin du cours, il existe des outils plus modernes et de plus haut niveau que make (qui est vraiment la base). L'un d'entre eux très répendu de nos jours est CMake. Si vous préférez continuer cet exercice avec CMake vous pouvez aller voir notre mini-tutoriel sur comment compiler avec CMake.
[fin de note.]

Dans un fichier (texte) qui s'appelle simplement « Makefile » (oui, comme ça, tout seul, sans extension), écrivez les deux lignes des dépendances de chacun des programmes factorielleRecursive et factorielleIterative (revoir le cours correspondant si nécessaire).

Ajoutez ensuite les lignes recommandées en cours:

CC = $(CXX)
CXXFLAGS = -std=c++11 -pedantic -Wall

La première va faire que l'édition de liens se fasse en C++ et non pas en C (qui est l'option par défaut).
La seconde vous permet de spécifier vos options de compilation (changez les comme vous le souhaitez).

Pour finir ajouter la dépendance

all: factorielleRecursive factorielleIterative
au début de votre Makefile

Essayer de compiler en tapant simplement

make

ou en lançant cette commande depuis votre IDE («Build» puis «Make all» dans Geany; voir la note ci-dessous).

Si vous avez un message comme

make: Nothing to be done for `all'.
c'est que vos programmes factorielleRecursive et factorielleIterative existent déjà (et donc make dit qu'il n'y a plus rien à faire).
Détruisez simplement ces fichiers (et les .o, tant qu'on y est) puis relancez make :
rm *.o factorielleRecursive factorielleIterative
make

NOTES :

  1. Il est très facile de compiler avec make dans Geany:

    • tapez Shift F9 pour faire « make » ;
    • ou alors Ctrl Shift F9 pour faire « make qqchose » (une fenêtre s'ouvre pour que vous puissiez entrer « qqchose »).

Autres exercices

Pour continuer à vous replonger dans le bain de la programmation, faîtes divers exercices que vous n'avez pas fait au premier semestre.

Quelques exemples :

Concernant l'utilisation de débogueur (outil pratique pour trouver des fautes), vous pouvez aller voir (ou revoir) l'exercice 3 de la dernière série du 1er semestre (aussi disponible ici sur ce site).

Autre possibilité pour vous occuper : si vous souhaitez passer à Qt Creator comme EDI pour le projet (et que vous ne l'avez pas utilisé au premier semestre), voyez:


Projet : Présentation

Allez lire ici, la présentation du projet.


Dernière mise à jour le 28 février 2023
Last modified: Tue Feb 28, 2023