Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

Vous n'avez pas encore de compte Developpez.com ? L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Developpez.com

C++

Choisissez la catégorie, puis la rubrique :

logo
Sommaire > Entrées / sorties avec les flux
        A quoi sert std::endl ?
        Comment saisir une chaîne contenant des espaces ?
        Comment obtenir la représentation hexadécimale d'un entier ?
        Comment obtenir un entier à partir de sa représentation hexadécimale ?
        Comment manipuler la représentation d'un nombre dans différentes bases ?
        Comment formater l'affichage sur les flux ?
        Comment utiliser les flux pour afficher ou saisir mes objets ?
        Comment surcharger correctement l'opérateur << pour afficher des objets polymorphes ?
        Comment effacer le contenu d'un ostringstream ?
        [Exemple] Comment convertir un tableau en chaîne ?
        Comment rediriger l'entrée ou la sortie standard ?
        Comment utiliser les itérateurs de flux ?
14.1. Manipulation de la console (6)
                Quelle est le différence entre #include <iostream.h> et #include <iostream> ?
                cout n'est pas reconnu à la compilation, que se passe-t-il ?
                Comment purger le buffer clavier ?
                Comment vérifier les valeurs saisies avec cin ?
                Comment faire une pause (attendre que l'utilisateur tape une touche) ?
                Est-il possible de simuler une saisie clavier ?
14.2. Manipulation des fichiers (11)
                Comment tester l'existence d'un fichier ?
                Comment savoir si la lecture / écriture dans un fichier a réussi ?
                Comment écrire à la suite d'un fichier existant ?
                Comment détecter la fin de fichier lors de la lecture ?
                Comment calculer la taille d'un fichier ?
                Comment fonctionnent les tests d'ouverture de fichier if ( fichier ) et if ( !fichier ) ?
                Comment faire pour lire un fichier ligne par ligne ?
                Comment lire l'intégralité d'un fichier texte dans un buffer ?
                Comment compter le nombre de lignes d'un fichier ?
                Pourquoi n'ai-je pas le nombre de caractères attendus avec mon fichier ?
                Comment effectuer des lectures / écritures binaires dans un fichier ?



A quoi sert std::endl ?
Mise à jour le 18/04/2005[haut]
auteurs : LFE, Aurélien Regat-Barrel
En plus de faire un retour à la ligne en ajoutant un caractère '\n', std::endl purge le buffer de sortie et force ainsi son écriture en appelant ostream::flush() (cela a le même fonctionnement que la fonction fflush() du C).
Les deux lignes de code suivantes sont donc équivalentes :
std::cout << "coucou" << std::endl;
std::cout << "coucou\n" << std::flush;
Il faut donc être prudent avec son utilisation, notamment avec les fichiers, car une opération de flush n'est pas gratuite. Son utilisation fréquente peut même sérieusement grever les performances en annulant tous les bénéfices d'une écriture bufferisée.


Comment saisir une chaîne contenant des espaces ?
Mise à jour le 03/02/2007[haut]
auteurs : Laurent Gomila, Luc Hermitte
L'opérateur >> de saisie d'une string permet de saisir des mots et donc considère les espaces comme des séparateurs. Pour saisir une chaîne entière contenant des espaces, il faut récupérer l'intégralité de la ligne au moyen de la fonction libre std::getline() définie dans <string> (et non pas avec la fonction membre cin.getline() qui opère sur des char*).
#include <iostream>
#include <string> 

std::string chaine; 
std::getline( std::cin, chaine );
A noter que si une variable a été extraite à l'aide de l'opérateur >> avant l'appel à std::getline, le caractère de fin de ligne peut subsister dans le flux d'entrée ; il peut donc être nécessaire de vider celui-ci avant d'extraire une nouvelle ligne (voir Comment purger le buffer clavier ?).

Remarque : l'implémentation de la fonction getline de la bibliothèque standard fournie par Microsoft avec Visual C++ 6.0 comporte un bug ; getline lit un caractère supplémentaire après la rencontre du délimiteur. Se référer au support Microsoft pour la correction de ce bug.


Comment obtenir la représentation hexadécimale d'un entier ?
Créé le 18/04/2005[haut]
auteur : Laurent Gomila
Le principe est le même que celui de la question Comment convertir un nombre en une string ?, sauf que l'on précise que l'on désire une représentation hexadécimale au moyen de std::hex.
#include <string> 
#include <sstream> 

int x = 127; 
std::ostringstream oss; 
oss << std::hex << x; 

std::string Hex = oss.str();
On peut de la même manière obtenir une représentation décimale (std::dec), ou octale (std::oct).


Comment obtenir un entier à partir de sa représentation hexadécimale ?
Créé le 18/04/2005[haut]
auteur : Laurent Gomila
Le principe est le même que celui de la question Comment convertir une string en un entier ?, sauf que l'on précise que l'on manipule une représentation hexadécimale au moyen de std::hex.
#include <string> 
#include <sstream> 

std::string Hex = "7F"; 
int x; 

std::istringstream iss( Hex ); 
iss >> std::hex >> x;
On peut de la même manière convertir une représentation décimale (std::dec), ou octale (std::oct).


Comment manipuler la représentation d'un nombre dans différentes bases ?
Créé le 18/04/2005[haut]
auteur : Laurent Gomila
Il existe dans la bibliothèque standard des manipulateurs de flux permettant de travailler dans l'une de ces trois bases :
  • décimale (std::dec)
  • hexadécimale (std::hex)
  • octale (std::oct)
Pour voir un exemple d'utilisation de ces manipulateurs, lisez Comment obtenir la représentation hexadécimale d'un entier ? et Comment obtenir un entier à partir de sa représentation hexadécimale ?.

Il n'existe aucun manipulateur pour la base 2 (binaire), mais on pourra y arriver au moyen de la classe std::bitset<>
#include <bitset>
#include <string>
#include <sstream>

int main()
{
    // Conversion binaire -> décimal
    std::bitset<8> b1( std::string( "01001011" ) );
    unsigned long x = b1.to_ulong(); // x = 75

    // Conversion décimal -> binaire
    std::bitset<8> b2( 75 );

    // Version 1 : un peu lourde à écrire
    std::string s1 = b2.to_string<
        char,
        std::char_traits<char>,
        std::allocator<char> >(); // s1 = "01001011"

    // Version 2 : un peu plus sympa
    std::ostringstream oss;
    oss << b2;
    std::string s2 = oss.str(); // s2 = "01001011"
}

Comment formater l'affichage sur les flux ?
Créé le 17/10/2005[haut]
auteur : Laurent Gomila
Il est possible, comme cela se faisait avec printf, de formater les informations envoyées sur un flux en utilisant ce que l'on appelle les manipulateurs de flux. Voici un petit topo (non exhaustif) des manipulateurs les plus utilisés :

Manipulateur Persistant Effet

Manipulateurs généraux
flush non Force le vidage du buffer du flux et son affichage
endl non Envoie une fin de ligne ('\n') ainsi qu'un flush
setw(n) non Spécifie que la prochaine sortie s'effectuera sur n caractères
setfill(c) oui Indique le caractère de remplissage pour setw
left non Aligne la sortie à gauche lors de l'utilisation de setw
right non Aligne la sortie à droite lors de l'utilisation de setw (comportement par défaut)

Formatage des nombres entiers
dec oui Injecte / extrait les nombres sous forme décimale
oct oui Injecte / extrait les nombres sous forme octale
hex oui Injecte / extrait les nombres sous forme hexadécimale
uppercase oui Affiche les lettres de la représentation hexadécimale en majuscule
nouppercase oui Affiche les lettres de la représentation hexadécimale en minuscule (annule l'effet d'uppercase)

Formatage des nombres flottants
setprecision(n) oui Spécifie le nombre de chiffres après la virgule affichés pour les nombres flottants non entiers (6 par défaut)
fixed oui Affiche les nombres flottants en notation décimale (opposé de scientific)
scientific oui Affiche les nombres flottants en notation scientifique (opposé de fixed)

Formatage des booléens
boolalpha oui Affiche les booléens sous forme alphabétique ("true" et "false" au lieu de "0" et "1")
noboolalpha oui Affiche les booléens sous forme de chiffre (annule l'effet de boolalpha)
Exemple

#include <iomanip>
#include <iostream>

using namespace std;

// Un petit tableau

// En-têtes de colonnes
cout << setfill(' ')
     << setw(15) << left << "Colonne 1"
     << setw(10) << left << "Colonne 2"
     << endl;

// Ligne 1
cout << setprecision(2) << fixed
     << setw(15) << left << 158.82589
     << setw(10) << left << 456.10288
     << endl;

// Ligne 2
cout << hex << uppercase
     << setw(15) << left << 255
     << setw(10) << left << 128
     << endl;

// Ligne 3
cout << boolalpha
     << setw(15) << left << true
     << setw(10) << left << false
     << endl;
A noter qu'il existe dans boost une bibliothèque de formatage style printf, mais plus évoluée et tirant partie des avantages offerts par le C++ (voir boost::format).


Comment utiliser les flux pour afficher ou saisir mes objets ?
Créé le 03/02/2007[haut]
auteur : Laurent Gomila
Pour injecter un objet de type quelconque dans un flux de sortie, il suffit de définir un opérateur << prenant en paramètre le flux, ainsi que l'objet à injecter.

#include <ostream>
#include <string>

class MaClasse
{
    friend std::ostream& operator <<(std::ostream&, const MaClasse&);

private :

    int Integer;
    std::string String;
};

std::ostream& operator <<(std::ostream& Stream, const MaClasse& Obj)
{
    Stream << Obj.Integer << " " << Obj.String;
    return Stream; // N'oubliez pas de renvoyer le flux, afin de pouvoir chaîner les appels
}

MaClasse Obj;
std::cout << "Ma classe : " << Obj << std::endl;
Notez qu'ici notre surcharge d'opérateur est déclarée amie de la classe, car elle a besoin d'accéder aux données privées de celle-ci. Cependant ce n'est pas obligatoire, notamment si les accesseurs adéquats ont été prévus dans la classe.

Le fonctionnement est le même pour l'extraction de valeurs à partir d'un flux d'entrée, via l'opérateur >> :

#include <istream>
#include <string>

class MaClasse
{
    friend std::istream& operator >>(std::istream&, MaClasse&);

private :

    int Integer;
    std::string String;
};

std::istream& operator >>(std::istream& Stream, MaClasse& Obj)
{
    Stream >> Obj.Integer >> Obj.String;
    return Stream; // N'oubliez pas de renvoyer le flux, afin de pouvoir chaîner les appels
}

MaClasse Obj;
std::cin >> Obj;
Le fait de prendre en paramètre un ostream ou un istream permettra d'utiliser nos surcharges avec n'importe quel type de flux (stringstream, fstream, ...) puisque ceux-ci dérivent tous des classes ostream (pour les flux d'entrée) et istream (pour les flux de sortie).

Notez bien que ce genre de surcharge ne peut pas être membre de la classe, car celà impliquerait que l'opérande gauche soit l'objet et non le flux.

Enfin, si vous devez gérer l'injection et l'extraction sur une hiérarchie d'objets polymorphes, il faudra mettre en place une petite astuce (voir Comment surcharger correctement l'opérateur << pour afficher des objets polymorphes ?).


Comment surcharger correctement l'opérateur << pour afficher des objets polymorphes ?
Créé le 18/04/2005[haut]
auteur : Laurent Gomila
Habituellement, pour pouvoir envoyer un objet sur un flux on surcharge l'opérateur << entre un ostream et le type de notre objet. Cependant, cette fonction ne peut être membre et de ce fait elle ne peut pas non plus être virtuelle. Par contre rien ne l'empêche d'appeler une fonction membre virtuelle de l'objet passé en paramètre. Ainsi, la manière habituelle de surcharger l'opérateur << pour une hiérarchie de classes est la suivante :
#include <iostream> 

class Base 
{ 
    friend std::ostream& operator << (std::ostream& O, const Base& B); 

    virtual void Print(std::ostream& O) const 
    { 
        O << "Je suis une base"; 
    } 
}; 

class Derivee : public Base 
{ 
    virtual void Print(std::ostream& O) const 
    { 
        O << "Je suis une derivee"; 
    } 
}; 

std::ostream& operator << (std::ostream& O, const Base& B) 
{ 
    B.Print(O); 
    return O; 
} 

Base* B1 = new Base, 
Base* B2 = new Derivee; 

std::cout << *B1 << std::endl; // "Je suis une base" 
std::cout << *B2 << std::endl; // "Je suis une derivee"

Comment effacer le contenu d'un ostringstream ?
Créé le 18/04/2005[haut]
auteur : Laurent Gomila
La fonction membre ostringstream::str a deux surcharges : une sans paramètre qui renvoie le contenu du flux sous forme de string, et une autre qui accepte une chaîne en paramètre pour réinitialiser le contenu du flux. Pour vider le flux il suffit donc d'appeler cette fonction avec comme paramètre la chaîne vide.
#include <sstream>
#include <string>

std::ostringstream oss; 
std::string Fichier[10]; 

// Génère une suite de noms de fichiers numérotés de 0 à 9 
for (int i = 0; i < 10; ++i) 
{ 
    oss.str(""); 
    oss << "Image_" << i << ".bmp"; 
    Fichier[i] = oss.str(); 
}
Note : on est souvent tenté d'utiliser la fonction clear, mais celle-ci n'a rien à voir : elle remet à zéro les bits d'erreur du flux.


[Exemple] Comment convertir un tableau en chaîne ?
Créé le 17/10/2005[haut]
auteurs : Laurent Gomila, Aurélien Regat-Barrel
De la même manière que dans Comment obtenir la représentation hexadécimale d'un entier ?, on peut obtenir la représentation hexadécimale d'un buffer de caractères en représentation hexadécimale à l'aide du manipulateur std::hex.

#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>

std::string array_to_string(const unsigned char* buffer, std::size_t size)
{
    std::ostringstream oss;

    // Afficher en hexadécimal et en majuscule
    oss << std::hex << std::uppercase;

    // Injecter tous les caractères sous forme d'entiers dans le flux
    std::copy(buffer, buffer + size, std::ostream_iterator<int>(oss, ""));

    return oss.str();
}
On utilise ici std::copy et std::ostream_iterator<int> pour envoyer les éléments du buffer un à un au flux, sous forme d'entiers. Le flux étant en mode hexadécimal, ceux-ci seront chacun correctement convertis. Le manipulateur std::uppercase sert quant à lui à obtenir une représentation des lettres hexadécimales en majuscule.

Si l'on souhaite personnaliser la représentation hexadécimale, on peut développer la boucle de copie comme ceci :

#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>

std::string array_to_string(const unsigned char* buffer, std::size_t size)
{
    std::ostringstream oss;

    // Afficher en hexadécimal et en majuscule
    oss << std::hex << std::uppercase;

    // Remplir les blancs avec des zéros
    oss << std::setfill('0');

    for (std::size_t i = 0; i < size; ++i)
    {
        // Séparer chaque octet par un espace
        if (i != 0)
            oss << ' ';

        // Afficher sa valeur hexadécimale précédée de "0x"
        // setw(2) permet de forcer l'affichage à 2 caractères
        oss << "0x" << std::setw(2) << static_cast<int>(buffer[i]);
    }

    return oss.str();
}

int main()
{
    const std::size_t size = 5;
    const unsigned char data[size] = {0x0C, 0x10, 0xFF, 0x00, 0xDA};
    std::cout << array_to_string(data, size) << '\n';
}
Le code ci-dessus produit le résultat suivant :

0x0C 0x10 0xFF 0x00 0xDA

Comment rediriger l'entrée ou la sortie standard ?
Créé le 03/02/2007[haut]
auteur : Laurent Gomila
Afin de rediriger l'entrée ou l'une des sorties standard (cin, cout, cerr ou clog) vers un autre flux, il suffit de réaffecter leur streambuf (le streambuf est l'objet qui fait le lien entre le flux et ce vers quoi il lit / écrit).

Afin d'accéder au streambuf d'un flux, il faut utiliser la fonction membre rdbuf (ses 2 surcharges pour être précis) :

// Récupérer le streambuf d'un flux
std::streambuf* std::ios::rdbuf();

// Changer le streambuf d'un flux
void std::ios::rdbuf(std::streambuf*);
Ainsi, pour rediriger cout vers un fichier par exemple, il suffira de procéder ainsi :

#include <fstream>
#include <iostream>

int main()
{
    std::cout << "Affichage sur la console"<< std::endl;

    // Redirection de std::cout vers le fichier Toto.txt
    std::ofstream Out("Toto.txt");
    std::streambuf* OldBuf = std::cout.rdbuf(Out.rdbuf());

    std::cout << "Affichage dans Toto.txt"<< std::endl;

    // Restauration du streambuf initial de std::cout (affichage sur la console)
    std::cout.rdbuf(OldBuf);

    return 0;
}
De cette manière vous n'êtes pas limité, cette méthode permet de rediriger n'importe quel flux vers n'importe quel autre.

A noter également que si vous ne souhaitez effectuer une telle redirection que ponctuellement et pour toute la durée de l'exécution, vous pouvez plus simplement utiliser une redirection au niveau de votre invite de commande (avec une syntaxe dépendante de l'OS) :

>MonProgramme.exe > Toto.txt

Comment utiliser les itérateurs de flux ?
Créé le 03/02/2007[haut]
auteur : Laurent Gomila
La STL propose deux classes pour itérer sur les flux : istream_iterator et ostream_iterator (définies dans l'en-tête <iterator>).

std::vector<int> Tab;
Tab.push_back(1);
Tab.push_back(3);
Tab.push_back(6);

// Plus besoin de boucle pour afficher les éléments du tableau :
std::copy(Tab.begin(), Tab.end(), std::ostream_iterator<int>(std::cout, "\n"));
Dans cet exemple, l'itérateur va parcourir les éléments du tableau un à un et utiliser l'opérateur << pour les injecter dans le flux passé en paramètre, en l'occurrence ici std::cout.
Le second paramètre de l'itérateur est simplement le délimiteur qui sera placé entre chaque élément.

Vous pouvez également utiliser les stream_iterator avec des classes quelconques, pourvu que leur opérateur << soit correctement défini.

Cela marche aussi dans l'autre sens : avec un std::istream_iterator vous pourrez extraire des valeurs / objets d'un flux les unes après les autres, et les placer par exemple dans un tableau.

// On va extraire à partir d'un fichier, par exemple
std::ifstream File("Data.txt");

// Méthode 1 : std::copy
std::vector<MaClasse> Tab1;
std::copy(istream_iterator<MaClasse>(File), istream_iterator<MaClasse>(), std::back_inserter(Tab1));
// std::back_inserter va remplacer les affectations par des push_back

// Méthode 2 : utiliser le constructeur prenant une paire d'itérateurs
std::vector<MaClasse> Tab2(istream_iterator<MaClasse>(File), (istream_iterator<MaClasse>()));
Un istream_iterator construit par défaut (comme le second ici) représentera toujours la fin du flux.

La paire de parenthèses a priori inutile autour du second istream_iterator est nécessaire : sans cela le compilateur croirait à une déclaration de fonction. Pour éviter cela vous pouvez également déclarer les variables correspondant aux itérateurs en dehors de l'appel :

istream_iterator<MaClasse> Begin(File);
istream_iterator<MaClasse> End;
std::vector<MaClasse> Tab2(Begin, End);
Pour les traitements sur des flux binaires (ie. ouvertes avec l'option binary), il vaudra mieux utiliser std::istreambuf_iterator, qui n'appliquera pas de traitement spécial aux caractères spéciaux.

lien : faq [Exemple] Comment manipuler un tableau de string ?


Consultez les autres F.A.Q.


Valid XHTML 1.0 TransitionalValid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2008 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Contacter le responsable de la rubrique C++

Partenaire : Hébergement Web