« Programmation C++/La librairie standard » : différence entre les versions

Contenu supprimé Contenu ajouté
→‎strlen : Lorsqu'une chaîne est enregistrée avec des unités de code de huit bits (soit un octet) la fonction strlen donne le nombre d'octets de la chaîne.
Ligne 1 :
{{Programmation C++ débutant}}
== Le cours du chapitre 12 : La classe string ==
== La STL ==
__TOC__
=== Présentation de la classe string ===
*Il s'agit d'une classe standard qui permet de représenter une chaîne de caractères.
*Pour l'utiliser, il faut rajouter #include <string>
*Cette classe encapsule des données pour pouvoir effectuer toutes les opérations de base sur les chaînes.
*Ces opérations sont assez complexes notamment la gestion de la mémoire : l'encapsulation permet de masquer à l'utilisateur de la classe toutes les difficultés techniques.
 
=== Différentes opérations sur la classe string ===
La STL (Standard Template Library) a été mise au point par [[w:Alexander Stepanov|Alexander Stepanov]] et [[w:Meng Lee|Meng Lee]]. La STL a été proposée au comité ISO de standardisation du C++ qui l'a acceptée en juillet 1994. Les résultats des travaux de recherche ont été publiés officiellement dans un rapport technique en novembre 1995. Ces travaux de recherche ont été une avancée majeure pour le C++, qui était aussi à l'époque le seul langage capable d'offrir les mécanismes de programmation générique nécessaires à la mise au point de cette bibliothèque. Elle a d'ailleurs influencé les autres parties de la future bibliothèque du C++ (notamment la future classe string) et aussi l'évolution du langage.
*'''Déclaration et initialisation : '''string s1; string s2= "BONJOUR";
*'''Affichage et saisie : ''' cout<<s2; cin>>s1;
*'''Concaténation : ''' string s3=s2+s1;
 
=== Exemple 1 : la classe string ===
La STL est axée autour de trois grands thèmes:
'''Fichier main.cpp'''
 
<source lang="cpp" line>
* Les '''conteneurs''': ce sont les structures de données classiques de l'algorithmique, à savoir les tableaux à accès direct, les listes chaînées, les piles, les files, les ensembles, les dictionaires. Dans sa version initiale, elle ne contiennent pas les tables de hachage, qui ne seront d'ailleurs pas présents dans ISO C++98.
#include <iostream>
* Les '''algorithmes''': ce sont les algorithmes classiques de l'algorithmique, essentiellement les algorithmes de tri et de recherche
#include <string>
* Les '''itérateurs''': c'est une généralisation du concept de pointeur. D'ailleurs un pointeur est un itérateur particulier. Les itérateurs ont l'avantage de pouvoir parcourir un conteneur sans que ce parcours ne fasse partie de l'état interne du conteneur.
 
using namespace std;
La force de la STL réside dans le fait de pouvoir offrir des conteneurs pouvant accueillir n'importe quel type moyennant quelques contraintes sémantiques qui peuvent varier selon le type conteneur et surtout dans le fait que les algorithmes sont complètement découplés des conteneurs (même si certains conteneurs offrent parfois leur propre algorithme pour des besoins d'optimisation et de performances. Par exemple, le conteneur ''list'' a une méthode ''sort'').
 
int main (void)
=== Les conteneurs ===
{
string s1, s2, s3;
 
cout << "Tapez une chaine : "; cin >> s1;
En c++, les conteneurs sont des classes offrant au programmeur une implémentation permettant de gérer des collections dynamiques d'objets du même type (on parle de conteneurs homogènes), c'est à dire pour lesquels le nombre d'objets contenus peut varier à l'exécution. Les conteneurs sont implémentés dans la bibliothèque standard en tant que ''modèles de classe'' (templates), ce qui permet de les utiliser avec n'importe quel type d'objets, standard ou défini par le programmeur (à l'exception de '''bitset''').
cout << "Tapez une chaine : "; cin >> s2;
s3 = s1 + s2;
cout << "Voici la concatenation des 2 chaines :" << endl;
cout << s3 << endl;
return 0;
}
</source>
 
De plus les conteneurs sont conçus de manière à être compatible avec les [[La librairie standard#Les algorithmes|algorithmes de la bibliothèque standard]].
 
====Explications====
Comme toute classe standard, il faut les inclure avec un en-tête (header) spécifique, qui est souvent le nom de la classe avec des < > autour. Exemple : pour utiliser la classe vector il faut préciser dans le programme un #include <vector> .
*Dans cet exemple, nous étudions l'utilisation de la classe string.
*On peut saisir le contenu d'un chaîne en utilisant cin.
*On peut concaténer 2 chaînes grâce à l'opérateur +.
*On peut afficher une chaîne grâce à cout.
*Dans cet exemple, on demande à l'utilisateur de saisir 2 chaînes de caractères s1 et s2 et on affiche s3 la concaténation de s1 et de s2.
 
====Exécution====
[[Image:Uml_diagram.png]]
Lorsqu'on exécute ce programme, il s'affiche à l'écran : <br/>
Tapez une chaîne : '''AZERTY''' <br/>
Tapez une chaîne : '''QSDFGH'''<br/>
Voici la concaténation des deux chaînes :<br/>
AZERTYQSDFGH
 
=== Séparateurs ===
Pour leur présentation il est d'usage de les séparer en trois catégories :
*Par défaut, lorsqu'on saisit une chaîne de caractères en utilisant cin, le séparateur est l'espace : cela empêche de saisir une chaîne de caractères comportant un espace.
==== Les conteneurs séquentiels ====
*La fonction getline(iostream &,string) permet de saisir une chaîne de caractères en utilisant le passage à la ligne comme séparateur : notre chaîne de caractères peut alors comporter des espaces.
une fonction saisi() qui permet de remplire la table clients par les données nécessaires
 
=== Exemple 2 : string avec des espaces ===
Ils offrent des fonctionnalités suffisantes de base pour gérer simplement des collections d'objets. Tous permettent une insertion et un accès à tous les éléments par des itérateurs.
 
<source lang="cpp" line>
Il s'agit de '''vector''', '''deque''', '''list''' et '''bitset'''.
#include <iostream>
using namespace std;
#include<string>
 
int main (void)
'''vector''' est un tableau dynamique où il est particulièrement aisé d'accéder directement aux divers éléments par un index, et d'en ajouter ou en retirer à la fin. A la manière des tableaux de type C, l'espace mémoire alloué pour un objet de type vector est toujours continu, ce qui permet des algorithmes rapides d'accès aux divers éléments. A noter qu'il existe une version spéciale de vector, vector<bool>, spécialement conçue pour économiser de la mémoire
{
string s1, s2, s3;
 
cout << "Tapez une chaine : "; getline (cin, s1);
'''deque''' (de "'''D'''ouble '''e'''nded '''que'''ue", file à double entrée) ressemble beaucoup à vector, mis à part qu'il est tout aussi efficace d'y insérer ou de supprimer des éléments au début de la liste. De plus, les éléments contenus ne sont pas forcément stockés de manière contigüe en mémoire, ce qui permet d'éviter de lourdes réallocations lors de changements importants dans le conteneur s'il est grand.
cout << "Tapez une chaine : "; getline (cin, s2);
s3 = s1 + s2;
cout << "Voici la concatenation des 2 chaines :" << endl;
cout << s3 << endl;
return 0;
}
</source>
 
'''list''' est une liste doublement chainée. L'insertion et la suppression d'élément ou de groupes continus d'éléments y est efficace partout dans la liste, mais il n'est pas possible d'accéder directement (par un index) aux différents éléments. On est forcé de les parcourir avec les itérateurs. De la meme manière que deque, une liste chaînée ne voit pas ses differents éléments stockés en mémoire continument.
 
====Explications====
'''bitset''' est un cas particulier de conteneur. On peut l'assimiler à un tableau classique de bool. Le chiffre binaire étant la plus petite unité de mémoire possible, alors que le type de base du c++ le plus petit (char) est de taille 8 bits (habituellement), ces tableaux sont donc particulièrement optimisés pour stocker et manipuler une grande quantité d'informations qui peuvent être traduites par 1 ou quelques bits seulement.
*Dans cet exemple, la chaîne de caractères s1 est saisie grâce à l'instruction getline(cin,s1) : cela permet de saisir au clavier la chaîne s1, la fin de la chaîne est alors indiquée lorsqu'on tape sur ENTREE.
*On saisit ensuite la chaîne s2 et on affiche la concaténation des deux chaînes.
 
==== Les conteneurs associatifs Exécution====
Lorsqu'on exécute ce programme, il s'affiche à l'écran :<br/>
Tapez une chaîne : '''AZ ERTY'''<br/>
Tapez une chaîne : '''QS DFGH'''<br/>
Voici la concaténation des deux chaînes :<br/>
AZ ERTYQS DFGH<br/>
 
=== Analyse de chaînes ===
Les conteneurs associatifs supposent l'utilisation d'une "clé de recherche" (un numéro d'identification, ou des chaines classées par ordre alphabétique par exemple) et implémentent des fonctions efficaces de tri et de recherche. Ils sont habituellement triés continuellement (lors de chaque insertion d'éléments).
*'''Nombre de caractères d'une chaîne : '''size() est une méthode de la classe string qui renvoie le nombre de caractères utiles.
*'''Récupération du i-ième caractère : '''la méthode const char at(int i) permet de récupérer le i-1ième caractère. (0 = 1er)
 
=== Exemple 3 : analyse de chaînes ===
Il s'agit de '''set''', '''multiset''', '''map''', '''multimap'''
 
<source lang="cpp" line>
'''set''' ne contient que des objets du type clé de recherche tandis que '''map''' contient des clés associées avec un autre objet de type différent (exemple : Les numéros de téléphone dans un annuaire sont triés selon le nom de l'abonné correspondant au numéro). Toutes les clés sont supposées uniques.
#include <iostream>
#include<string>
 
using namespace std;
Les conteneurs '''multiset''' et '''multimap''' sont les versions correspondantes qui autorisent la présence de plusieurs clés identiques (avec des algorithmes correspondants nécessairement un peu moins performants).
 
int main (void)
==== Les adaptateurs de conteneurs ====
{
Les adaptateurs de conteneurs ne s'utilisent qu'en complément à un des conteneurs précédents, afin de lui ajouter des fonctionnalités plus précises.
string s= "BONJOUR";
int i, taille = s.size ();
 
cout << "La chaine comporte " << taille << " caracteres." << endl;
Il s'agit de '''stack''', '''queue''', '''priority_queue'''
 
for (i = 0 ; i < taille ; i++)
'''stack''' implémente une interface de pile (LIFO, Last In First Out : dernier arrivé, premier sorti).
cout << "caractère " << i << " = " << s.at(i) << endl;
return 0;
}
</source>
 
'''queue''' implémente un interface de file d'attente (FIFO, First In First Out : premier arrivé premier sorti).
 
==== Explications ====
'''priority_queue''' implémente un interface de file d'attente où les éléments peuvent être comparés entre eux (par niveau de ''priorité''), et sont classés dans la file suivant l'ordre spécifié. Ainsi elle permettent de traiter des données suivant des niveaux de priorité de manière efficace.
*La méthode size() sur un string permet de connaître la taille d'une chaîne de caractères.
*Si i est un entier s.at(i) permet de connaître le (i+1)-ième caractère de la chaîne (s.at(0) étant le premier caractère).
*Dans ce programme, on initialise la chaîne s à "BONJOUR" : on affiche ensuite la taille de la chaîne et on affiche ensuite un à un chaque caractère.
 
==== Les algorithmesExécution ====
Lorsqu'on exécute ce programme, il s'affiche à l'écran :
La chaîne comporte 7 caractères
caractère 0 = B
caractère 1 = O
caractère 2 = N
caractère 3 = J
caractère 4 = O
caractère 5 = U
caractère 6 = R
 
=== Compatibilité avec les char * et les tableaux de char ===
==== Les algorithmes de séquences non modifiants ====
*'''Transformation de chaîne de type C en string :''' on peut utiliser le constructeur string(char *) ou l'affectation grâce au symbole = d'un char * vers une string.
* '''for_each'''
*'''Transformation d'une string en chaîne de type C : ''' il suffit d'utiliser la méthode : c_str() qui renvoie un char * qui est une chaîne de type C.
* '''find'''
* '''find_if'''
* '''find_end'''
* '''find_first_of'''
* '''adjacent_find'''
* '''count'''
* '''count_if'''
* '''mismatch'''
* '''equal'''
* '''search'''
* '''search_n'''
==== Les algorithmes de séquences modifiants ====
===== copies =====
* '''copy'''
* '''copy_backward'''
===== échanges =====
* '''swap'''
* '''swap_ranges'''
* '''iter_swap'''
===== transformations =====
* '''transform'''
===== remplacements =====
* '''replace'''
* '''replace_if'''
* '''replace_copy'''
* '''replace_copy_if'''
===== remplissages =====
* '''fill'''
* '''fill_n'''
===== générations =====
* '''generate'''
* '''generate_n'''
===== suppressions =====
* '''remove'''
* '''remove_if'''
* '''remove_copy'''
* '''remove_copy_if'''
===== éléments uniques =====
* '''unique'''
* '''unique_copy'''
===== ordre inverse =====
* '''reverse'''
* '''reverse_copy'''
===== rotations =====
* '''rotate'''
* '''rotate_copy'''
===== permutations aléatoires =====
* '''random_shuffle'''
===== répartitions =====
* '''partition'''
* '''stable_partition'''
==== Les algorithmes de tri et les opérations apparentées ====
===== tris =====
* '''sort'''
* '''stable_sort'''
* '''partial_sort'''
* '''partial_sort_copy'''
* '''nth_element'''
===== recherches dichotomiques =====
* '''lower_bound'''
* '''upper_bound'''
* '''equal_range'''
* '''binary_search'''
===== fusions =====
* '''merge'''
* '''inplace_merge'''
===== opérations d'ensemble =====
* '''includes'''
* '''set_union'''
* '''set_intersection'''
* '''set_difference'''
* '''set_symmetric_difference'''
===== opérations de tas =====
* '''push_heap'''
* '''pop_heap'''
* '''maxmake_heap'''
* '''sort_heap'''
===== minimum et maximum =====
* '''min'''
* '''max'''
* '''min_element'''
* '''max_element'''
* '''lexicographical_compare'''
===== permutations =====
* '''next_permutation'''
* '''prev_permutation'''
 
=== Exemple 4 : compatibilité avec les tableaux de char et les char * ===
== Les chaînes de caractères ==
=== La classe string ===
=== Les chaînes de caractères de type C ===
Le header cstring défini un certain nombre de fonction permettant la manipulation de chaînes de caractères de type C.
==== memcpy ====
====memmove====
==== strcpy ====
====strncpy ====
==== strcat ====
====strncat====
==== memcmp ====
====strcmp====
==== strcoll ====
====strncmp====
==== strxfrm ====
====strcspn====
==== strspn ====
====strtok====
==== memset ====
====strerror====
==== strlen ====
 
<source lang="cpp" line>
Lorsqu'une chaîne est enregistrée avec des unités de code de huit bits (soit un octet) la fonction strlen donne le nombre d'octets de la chaîne.
#include <iostream>
using namespace std;
#include<string>
 
int main (void)
Si jamais le codage de caractère utilisé est l'un de ses anciens codage de caractères où le nombre d'octet correspond au nombre de caractères, ce nombre est donc alors aussi le nombre de caractères.
 
<source lang="cpp">
int strlen(char *str)
{
intstring s1, is2;
char c1 []= "BONJOUR";
const char * c2;
 
is1 = 0c1;
cout << s1 << endl;
while(str[i] != '\0')
s2 = i++"AU REVOIR";
returnc2 = s2.c_str(i);
cout << c2 << endl;
return 0;
}
</source>
 
====memchr====
<source lang="cpp">
char *pch;
int pospex;
 
====Explications====
pch = (char*) memchr (Trame, '!', strlen(Trame));
*Dans cet exemple, c1 est un tableau de 8 char contenant la chaîne "BONJOUR" (n'oubliez pas le caractère de fin de chaîne '\0').
if(pch!=NULL)
*Le pointeur c2 est un pointeur vers un tableau non modifiable de char.
*Les variables s1 et s2 sont des string.
*On peut affecter directement s1=c1 : le tableau de char sera transformé en string.
Dans c2, on peut récupérer une chaîne « de type C » identique à notre string en écrivant c2=s2.c_str().
*On peut transformer aisément une string en tableau de char et inversement.
 
====Exécution====
Lorsqu'on exécute ce programme, il s'affiche à l'écran : <br/>
BONJOUR<br/>
AU REVOIR<br/>
 
=== Transformation d'une chaîne en int ou double ===
*Pour transformer une chaîne en double ou en int, il faut transformer la chaîne en flot de sortie caractères : il s'agit d'un istringstream.
*Ensuite, nous pourrons lire ce flot de caractères en utilisant les opérateurs usuels >>.
*La méthode eof() sur un istringstream permet de savoir si la fin de la chaîne a été atteinte.
*Chaque lecture sur ce flot grâce à l'opérateur >> renvoie un booléen qui nous indique d'éventuelles erreurs.
 
=== Exemple 5 : transformation de string en int ===
 
<source lang="cpp" line>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main (void)
{
string s;
pospex = pch - Trame;
cout << "Tapez une chaine : "; getline (cin, s);
istringstream istr(s);
int i;
 
if (istr >> i) cout << "VOUS AVEZ TAPE L'ENTIER " << i << endl;
else cout << "VALEUR INCORRECTE" << endl;
return 0;
}
</source>
 
==== memchr(void* p, int c, size_t n) ====
#
 
memchr scrute les n premiers octets de p à la recherche du caractère c.
 
====Explications====
# Valeur renvoyée :
*Dans cet exemple, s est une chaîne : on saisit une chaîne au clavier en utilisant getline(cin,s).
*On crée ensuite un istringstream appelé istr et construit à partir de s.
*On peut lire un entier i à partir de istr en utilisant : istr>>i .
*(istr>>i) renvoie true si un entier valide a pu être lu et renvoie false sinon.
*De la même manière, on pourrait lire des données d'autres types, double par exemple.
 
====Exécution 1====
si succès, renvoie un pointeur sur la première occurrence de c dans p, sinon, renvoie NULL.
Lorsqu'on exécute ce programme, il s'affiche à l'écran : <br/>
Tapez une chaîne : '''12345''' <br/>
VOUS AVEZ TAPE L'ENTIER 12345
 
====Exécution 2====
==== inline char* strchr(char* s1, int __n) ====
Lorsqu'on exécute ce programme, il s'affiche à l'écran : <br/>
==== inline char* strpbrk(char* s1, const char* s2) ====
Tapez une chaîne : '''BJ9UYU'''<br/>
==== inline char* strrchr(char* s1, int n) ====
VALEUR INCORRECTE <br/>
==== inline char* strstr(char* s1, const char* s2) ====
 
== EXERCICES ==
[[Catégorie:Programmation C++ (livre)]]
=== EXERCICE 1 ===
On veut écrire une classe Note qui est représentée par 3 données membres : 2 chaînes de caractères nom et prénom et un entier v qui est la valeur de la note. Grâce au constructeur par défaut la note est initialisée ainsi : le nom et le prénom sont à la chaîne vide et la valeur note vaut 0. <br/>
Pour pouvoir accéder à la valeur du nom, prénom et de la note il y a un accesseur. Un unique mutateur permet de modifier le nom, le prénom et la valeur de la note mais il doit respecter les contraintes suivantes : <br/>
Le nom et le prénom ne peuvent pas être la chaîne vide. <br/>
La note est comprise entre 0 et 20 bornes incluses <br/>
Le mutateur renvoie un booléen true si tout s'est bien passé false sinon.<br/>
On peut afficher la note grâce à l'opérateur << et en saisir une grâce à l'opérateur >>.
On écrira une classe menu qui gérer notre une note de la manière suivante :<br/>
1. Afficher la note<br/>
2. Modifier la note<br/>
0. Quitter<br/>
Écrire le programme principal qui crée notre note et qui appelle notre menu.<br/>