---
jupytext:
  text_representation:
    extension: .md
    format_name: myst
    format_version: 0.13
kernelspec:
  display_name: C++17
  language: C++17
  name: xcpp17
---

+++ {"tags": ["solution"]}

# Exercice : Pointeurs, structures et références

:::{attention}
Dans cet exercice, les pointeurs et les références sont utilisés en fonction de ce qui
est le plus approprié. Il est important d'être attentif au type des paramètres afin de ne
pas faire d'erreurs. N'oubliez pas de bien tester chacune de vos fonctions au fur et à
mesure.
:::

Le but de cet exercice est de réaliser un système basique permettant à un fabriquant de
voitures de gérer son stock ainsi que les garages exposant ses véhicules.

Le type `Garage` enregistre le nom et la capacité d'exposition d'un garage ainsi que le
nombre de véhicules actuellement exposés et le chiffre d'affaire effectué. Le type
`Voiture` quant à lui enregistre le code de la voiture, son prix et éventuellement un
pointeur vers le garage où elle est exposée. Si la voiture n'est pas actuellement exposé
ce pointeur doit avoir la valeur `NULL`.

Ces structures sont définies ci-dessous :

```cpp
struct Garage {
    string nom;
    int nbvoitures;
    int capacite;
    int CA;
};
struct Voiture {
    string code;
    float prix;
    Garage *position;
};
```

Sur le même modèle que dans l'exercice 6 du TD4 (Fournitures), on utilisera des vecteurs
de structures pour enregistrer la liste des garages et des voitures :

```cpp
vector<Voiture> stock;
vector<Garage>  lieux;
```

1. Définissez la fonction `ajouteVoiture` qui prend en paramètre une référence vers le
   stock, le code et le prix d'une voiture et qui ajoute dans le stock une nouvelle
   voiture actuellement non exposée.

   `void ajouteVoiture(vector<Voiture> &stock, string code, float prix);`

   BEGIN SOLUTION

   ```cpp
   void ajouteVoiture(vector<Voiture> &stock, string code,
                      float prix) {
       Voiture v;
       v.code     = code;
       v.prix     = prix;
       v.position = NULL;
       stock.push_back(v);
   }
   ```

   END SOLUTION

2. De manière similaire, définissez maintenant une fonction `ajouteGarage` qui prend en
   paramètre une référence vers la liste des lieux d'exposition, un nom et une capacité,
   et qui ajoute un nouveau garage. Le nombre de voitures exposées et le chiffre
   d'affaire seront initialisés à zéro.

   `void ajouteGarage(vector<Garage> &lieux, string nom, int capacite);`

   BEGIN SOLUTION

   ```cpp
   void ajouteGarage(vector<Garage> &lieux, string nom,
                     int capacite) {
       Garage g;
       g.nom        = nom;
       g.capacite   = capacite;
       g.nbvoitures = 0;
       g.CA         = 0;
       lieux.push_back(g);
   }
   ```

   END SOLUTION

3. Définissez maintenant deux fonctions permettant d'afficher la liste des voitures du
   stock ainsi que la liste des lieux d'exposition. Lors de l'affichage d'une voiture, si
   celle-ci est exposée dans un garage, vous afficherez le nom de celui-ci.

   `void afficheStock(vector<Voiture> stock);`

   `void afficheLieux(vector<Garage> lieux);`

   BEGIN SOLUTION

   ```cpp
   void afficheStock(vector<Voiture> stock) {
       for (int i = 0; i < stock.size(); i++) {
           Voiture v = stock[i];
           cout << "la voiture " << v.code << " vendue "
                << v.prix << " kopek";
           if (v.position == NULL) {
               cout << " n'est actuellement pas exposée." << endl;
           } else {
               cout << " est visible au garage " << v.position->nom
                    << "." << endl;
           }
       }
   }
   void afficheLieux(vector<Garage> lieux) {
       for (int i = 0; i < lieux.size(); i++) {
           Garage g = lieux[i];
           cout << "le garage " << g.nom << " expose actuellement "
                << g.nbvoitures << " voiture(s) et a un CA de "
                << g.CA << endl;
       }
   }
   ```

   Remarque: Ici on n'a pas besoin de passage par référence, mais si on veut éviter la
   copie d'une grosse donnée (tableau de structures) on pourrait passer les paramètres
   par références constantes.

   END SOLUTION

Nous allons maintenant définir deux fonctions outils permettant de faire des recherches
dans le stock et les lieux d'expositions. Ces fonctions permettent de trouver un élément
particulier et le renvoient s'il existe. Afin que les fonctions appelantes puissent
modifier les éléments trouvés, il est nécéssaire de renvoyer non pas des copies de ces
éléments mais des pointeurs vers les originaux.

4. Définissez la fonction `chercheVoiture` qui parcourt le stock à la recherche d'une
   voiture dont le code est donné et renvoie un pointeur vers la structure représentant
   cette voiture. Si aucune voiture ne correspond dans le stock, la fonction renvoie un
   pointeur `NULL`.

   `Voiture *chercheVoiture(vector<Voiture> &stock, string code);`

   BEGIN SOLUTION

   Ici on a besoin de passage par référence, car on veut renvoyer un pointeur sur la
   voiture cherchée. Si on ne fait pas un passage par référence, on aurait un pointeur
   sur une copie temporaire du tableau des voitures, qui ne serait plus alloué en sortie
   de la fonction.

   ```cpp
   Voiture *chercheVoiture(vector<Voiture> &stock, string code) {
       for (int i = 0; i < stock.size(); i++)
           if (stock[i].code == code)
               return &stock[i];
       return NULL;
   }
   ```

   Autre solution:

   ```cpp
   Voiture *chercheVoiture(vector<Voiture> &stock, string code) {
       Voiture *p = NULL;
       for (int i = 0; i < stock.size(); i++) {
           if(code == stock[i].code){
               *p = stock[i];
           }
       }
       return p; // non pas *p, mais p (on doit renvoyer un
                 // pointeur, pas une valeur sur laquelle pointe
                 // un pointeur)
   }
   ```

   END SOLUTION

5. Définissez la fonction `chercheGarage` qui parcourt la liste des lieux d'exposition
   afin de trouvez un garage disposant de place pour exposer une voiture et renvoie un
   pointeur vers la structure le représentant. Si tous les garages sont actuellement
   pleins, la fonction renvoie un pointeur `NULL`.

   `Garage *chercheGarage(vector<Garage> &lieux);`

   BEGIN SOLUTION

   ```cpp
   Garage *chercheGarage(vector<Garage> &lieux) {
       for (int i = 0; i < lieux.size(); i++)
           if (lieux[i].nbvoitures < lieux[i].capacite)
               return &lieux[i];
       return NULL;
   }
   ```

   END SOLUTION

Nous allons maintenant utiliser ces fonctions afin d'implémenter les outils nécessaires à
la gestion du parc de voitures.

6. Définissez la fonction `exposeVoiture` qui cherche une voiture de code donné dans le
   stock et la met en exposition dans un garage si :

   - une voiture avec ce code existe ;
   - elle n'est pas déjà exposée ;
   - un garage dispose de place pour l'exposer.

   Si toutes les conditions sont remplies, toutes les structures concernées doivent êtres
   mises-à-jour et la valeur `true` renvoyée. Sinon, aucune modification ne doit être
   réalisée et la valeur `false` doit être renvoyée.

   `bool exposeVoiture(vector<Voiture> &stock, vector<Garage> &lieux, string code);`

   BEGIN SOLUTION

   ```cpp
   bool exposeVoiture(vector<Voiture> &stock, vector<Garage> &lieux,
                      string code) {
       Voiture *v = chercheVoiture(stock, code);
       // Test si non existante ou déjà exposée
       if (v == NULL || v->position != NULL)
           return false;
       Garage *g = chercheGarage(lieux);
       if (g == NULL)
           return false;
       v->position = g;
       g->nbvoitures++;
       return true;
   }
   ```

   END SOLUTION

7. Définissez la fonction `vendVoiture` qui marque une voiture de code donné comme
   n'étant plus exposée, met à jour les informations du garage qui l'exposait, et renvoie
   `true` si une voiture de ce code existe et est exposée; dans le cas contraire aucune
   modification n'a lieu et `vendvoiture` renvoie `false`.

   `bool vendVoiture(vector<Voiture> &stock, string code);`

   BEGIN SOLUTION

   ```cpp
   bool vendVoiture(vector<Voiture> &stock, string code) {
       Voiture *v = chercheVoiture(stock, code);
       if (v == NULL || v->position == NULL)
           return false;
       v->position->nbvoitures - -;
       v->position->CA += v->prix;
       v->position = NULL;
       return true;
   }
   ```

   END SOLUTION
