© 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 :
exo_01
Ecrire la fonction Exo_01() qui, dans une boucle :
Compiler et tester.
Corrigés : exo_01.cxx
exo_02
Ecrire la fonction Exo_02() qui, dans une boucle :
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
exo_03
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 :
Corrigés : exo_03.cxx - config.h
exo_04
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 :
Compiler et tester.
Compiler et tester.
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).
Compiler et tester.
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.
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
exo_05
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
[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