Exercice : Pointeurs, structures et références

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 :

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 :

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

    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

    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

    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.

  1. 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.

    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:

    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

  2. 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

    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.

  1. 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

    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

  2. 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

    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