C++ : TP 3 - Classe conteneur vector

© D. Mathieu     mathieu@romarin.univ-aix.fr
I.U.T.d'Aix en Provence - Département Informatique
Créé le 10/01/2000 - Dernière mise à jour : 25/01/2001

Remarques préliminaires :

Sommaire

Histogramme de chaînes  exo_01
Vecteur de chaînes  exo_02
Vecteur de chaînes (suite) - itérateurs  exo_03
Fonctions membres de la classe vector
Constructeurs
Remplissage du vecteur
Fonction resize()
Fonction clear()
Fonction reserve()
Autres fonctions : assign(), swap(), erase()
 exo_04
Comparaison de vecteurs  exo_05

Histogramme de chaînes

exo_01
    Le but de cet exercice est de compter le nombre de chaînes de caractères d'un fichier qui appartiennent à la même classe d'équivalence. On posera que les chaînes de longueur 0 à N-1 inclus appartiennent à la première classe (classe 0), que les chaînes de longueur N à 2N-1  inclus appartiennent à la deuxième classe (classe 1), etc... On appellera CstIntervalle le nombre de valeurs différentes d'une même classe, et CstNbreClasses le nombre total de classes comptabilisées. On peut par exemple prendre des classes d'équivalence de 10 en 10 caractères (classe 0 = chaînes de longueur entre 0 et 9, classe 1 = chaînes de longueur entre 10 et 19, etc.), et rejeter toutes les chaînes de longueur >= 80.

    Ecrire la fonction Exo_01() qui, dans une boucle :

    En fin de boucle (fin de fichier source), afficher les effectifs de chaque classe d'équivalence, le nombre de lignes rejetées et le nombre total de lignes lues. Soigner l'affichage pour que tous les nombres de lignes soient alignés sur les unités. Vérifier la cohérence des résultats affichés. En cas d'incohérence, afficher un message d'erreur dans le flux cerr.

    Compiler et tester.

Corrigés : exo_01.cxx

Sommaire


Vecteur de chaînes

exo_02
    Le but de cet exercice est de stocker les différentes chaînes d'un fichier dans un conteneur générique vector, instancié par le "type" string sous la forme : vector <string>.

    Ecrire la fonction Exo_02() qui, dans une boucle :

    Inclure le fichier <vector>. En fin de boucle (fin de fichier source), afficher les différents éléments du vecteur en utilisant l'opérateur membre [].

    Attention : la condition de sortie de la boucle d’édition consiste à comparer l’indice de boucle (i par exemple) à la taille du vecteur renvoyée par la fonction size(). Le type de la valeur de retour de cette fonction, donc le type de i, est size_type,  type exporté par la classe vector <string>. La déclaration de i doit donc être :
 
vector<string>::size_type i;

    Afficher le premier et le dernier élément du vecteur au moyen des fonctions membres front() et back().

    Compiler et tester.

Corrigés : exo_02.cxx

Sommaire


Vecteur de chaînes (suite) - itérateurs

exo_03
    Au moyen de la directive de précompilation #define, créer une macro classdef équivalente à l'instruction typedef.

    Définir un nouveau type utilisateur CVString par instanciation de la classe vector par la classe string.

    Ecrire la fonction Exo_03() qui, dans une boucle :

    En fin de boucle (fin de fichier source), afficher les différents éléments du vecteur :     Compiler et tester.

Corrigés : exo_03.cxx      -      config.h

Sommaire


Fonctions membres de la classe vector

exo_04
    Cet exercice est destiné à tester l’utilisation et les effets de quelques autres fonctions membres disponibles dans la classe générique vector.

    Comme la classe string, la classe générique vector offre les accesseurs size(), max_size(), capacity() et empty(), avec la même sémantique (la même signification et la même utilisation).

    Recopier le fichier exo_03.cxx dans le fichier exo_04.cxx dans lequel vont être effectuées différentes opérations.

    Dans l'espace de noms anonyme, ajouter la fonction EditSizes() analogue à la même fonction écrite dans le fichier dirstring/exo_02.cxx, et à laquelle est passé par référence un paramètre donnée de type "vecteur de chaînes". En fait, comme max_size() renvoie toujours le même résultat, l'appel à cette fonction pourra être supprimé après le premier essai.

    Dans l'espace de noms anonyme, ajouter la fonction EditVString() à laquelle sont passés par référence deux paramètres données :

    Cette fonction affiche le titre, le contenu du vecteur (en récupérant l'une des boucles de Exo_03()), puis les caractéristiques du vecteur. Après chacune des opérations demandées ci-dessous, la fonction EditVString() sera appelée.

Sommaire

Constructeurs : vecteur vide, constructeur par défaut, vecteur préinitialisé, constructeur par recopie

    Créer un vecteur vide, VString, un vecteur de 2 éléments non précisés, un vecteur de 5 éléments initialisés à une valeur passée en paramètre (de type NTCTS ou string), et un vecteur par recopie du précédent. Les afficher.

     Compiler et tester.

Sommaire

Remplissage du vecteur

    Comme dans Exo_03(), remplir le vecteur VString à partir d'un fichier. L'afficher. Le sauvegarder dans un vecteur VSave.

     Compiler et tester.

Sommaire

Fonction resize()

    Modifier le vecteur VString en utilisant resize() avec une valeur < 5, puis avec une valeur > 9. L'afficher dans les deux cas.

     Compiler et tester.

     Lorsqu'on analyse les résultats de ces deux opérations, on constate que la fonction resize() utilisée avec une taille inférieure à la taille courante diminue la taille mais ne modifie pas la capacité du vecteur, alors qu'utilisée avec une taille supérieure à la taille courante, la nouvelle taille et la capacité sont ajustées à cette nouvelle valeur. De plus, les nouveaux éléments du vecteur sont initialisés par le constructeur par défaut du type ayant servi à l'instanciation (ici une chaîne vide).

Sommaire

Fonction clear()

    Purger le vecteur VString en utilisant clear(). L'afficher.

     Compiler et tester.

Sommaire

Fonction reserve()

    Réserver une taille du vecteur VString en utilisant reserve(), successivement avec une valeur inférieure, puis une valeur supérieure à sa capacité courante. L'afficher dans les deux cas.

     Compiler et tester.

     Lorsqu'on analyse les résultats de ces deux opérations, on constate que la fonction reserve() utilisée avec une valeur inférieure à la capacité courante est sans effet, alors qu'utilisée avec une valeur supérieure à la capacité courante, celle-ci est ajustée à cette nouvelle valeur.

Sommaire

Autres fonctions : assign() [4], swap(), erase()

    Tester la fonction membre swap() et la fonction globale swap() entre deux vecteurs.

    Tester la fonction membre erase() sur le vecteur VSave, en supprimant 3 éléments à partir du deuxième.

     Compiler et tester.

Corrigés : exo_04.cxx

Sommaire


Comparaison de vecteurs

exo_05
    Dans l'espace de noms anonyme, écrire la fonction Compare() à laquelle sont passés en paramètres l'identificateur d'un vecteur V1 (un string), le vecteur V1 lui-même de type CVString, l'identificateur d'un vecteur V2 (un string) et le vecteur V2 lui-même. Cette fonction affiche le résultat de la comparaison des deux vecteurs : V1 < V2 ou V1 == V2 ou V1 > V2.

    Ecrire la fonction Exo_05() qui, dans une boucle, stocke chaque ligne d'un fichier dans un vecteur de chaînes dans l'ordre de lecture (voir Exo_02()), et dans un autre vecteur dans l'ordre inverse (Exo_03()).

    En fin de boucle, comparer les deux vecteurs en utilisant la fonction Compare() décrite ci-dessus.

    Compiler et tester.

    Transférer le contenu du premier vecteur dans un troisième vecteur, au moyen de l'opérateur d'affectation = de la classe CVString, hérité de la classe générique vector. Comparer ces deux vecteurs.

    Compiler et tester.

    Inverser le contenu du premier vecteur en utilisant la fonction reverse(). Ne pas oublier d'inclure le fichier <algorithm> qui contient le prototype de cette fonction. Comparer ce vecteur avec le deuxième.

    Compiler et tester.

    Supprimer le dernier élément du deuxième vecteur au moyen de la fonction pop_back(). Comparer le premier vecteur au deuxième.

    Compiler et tester.

Corrigés : exo_05.cxx

Sommaire


Téléchargement des corrigés :

tpvector.zip

Chemins d'accès aux sources des corrigés :

~mathieu/PARTAGE/src/tp/tpC++/tpvector/dirvector


[1] En principe, il est possible de remplacer l'opérateur membre [] par la fonction membre at(), mais en pratique, cette fonction n'est pas implémentée dans les bibliothèques du C++ utilisées actuellement au département. Cette fonction est implémentée dans le compilateur Borland C++ 5.5. Pour faciliter les tests des exercices avec ce compilateur, il est intéressant de créer un fichier config.h définissant soit la macro GCC, soit la macro BCC55, et d'ajouter dans la fonction Exo_03() un test de la fonction at() soumis à compilation conditionnelle.

    Dans ce cas, ne pas oublier de recopier le fichier Config.h dans le répertoire courant, et ajouter au fichier source la ligne :

    #include "Config.h"

[2] const_iterator car l'objet désigné par cet itérateur ne sera pas modifié (il s'agit d'une simple édition).

[3] Dans le fichier g++-2/stl_iterator.h du compilateur g++, qui contient l'implémentation des itérateurs, il semble que la classe const_reverse_iterator soit mal implémentée. Une erreur de compilation apparaît en effet systématiquement lors de son utilisation. En conséquence, utiliser à la place reverse_iterator.

    Si vous utilisez le compilateur Borland C++ 5.5, la classe const_reverse_iterator semble implémentée (quoique introuvable dans le fichier include/iterator.h), mais l'utilisation des opérateurs de comparaison (en particulier != nécessaire ici) provoque une erreur de compilation à la ligne {1} de la séquence suivante :

    for (CVString::const_reverse_iterator i (VString.rbegin ());
         i != VString.rend (); ) // {1}
        cout << *i++ << endl;

     Cela est probablement dû au fait que le compilateur utilise l'opérateur générique !=, qui suppose que les deux opérandes sont de même type. Or i est de type const_reverse_iterator alors que rend() renvoie un reverse_iterator.

     La solution consiste donc à ranger le résultat de rend() dans une constante et à utiliser cette dernière dans le test, comme le montre le corrigé. Et ça marche !!!

     Cette solution est de toutes façons préférable, car, le vecteur n'évoluant pas dans la boucle, il est inutile de réévaluer la fonction à chaque itération.

[4] N'est pas implémentée dans le compilateur g++; mais existe dans le compilateur Borland C++ 5.5.

© D. Mathieu     mathieu@romarin.univ-aix.fr
I.U.T.d'Aix en Provence - Département Informatique