1- introduction Les flux d'entrées/sorties en C++ En langage C-ANSI, la librairie d'entrées/sorties (stdio) fournie des fonctions d'entrées/sorties sur les 3 flux d'entrées/sorties standards (stdin, stdout et stderr) putchar(), puts(), printf() ios_base getchar(), gets(), scanf() De même, en langage C++, la librairie SL (Standard Library) fourni un ensemble de classes permettant des entrées/sorties sur les 3 flux d'entrées/sorties standards (stdin, stdout et stderr) les classes istream (objet cin), ostream (objets cout, cerr et clog). Le diagramme de classe ci-dessous montre les relations entre ces classes. basic_ios En réalité, ces noms sont des alias vers les classes basic_ostream et basic_istream et sont définis par les instructions typedef basic_ istream <char> istream; typedef basic_ ostream <char> ostream; basic_istream basic_ostream exemple cout << "Hello world!" << endl; Sur Visual Stusio, on trouvera l'aide sur l'opérateur "<<" dans l'aide en ligne de la classe basic_ostream. istream ostream L écriture <char> derrière les noms de classes signifie qu un mécanisme de template est utilisé par ces classes et que type de donnée utilisé pour les buffer est char pour les istream & ostream. A ne pas confondre cette écriture avec un cast (voir cours C++ 1 ère année chapitre 2 des variables de bases) Les template seront vus dans un cours ultérieur. 2-Les flux d'entrées/sorties standards Ici aussi, les 3 même flux standards sont ouverts cin objet, instance de la classe istream, c'est l'entrée standard (clavier). cout objet, instance de la classe ostream, c'est la sortie standard (écran). cerr objet, instance de la classe ostream, c'est la sortie standard pour les messages d'erreurs (écran). fig 2 exemple char nom[100]; cout << "Tapez votre nom "; cin >> nom; cout << "Bonjour M. " << nom << endl; 3 - Les sorties 3.1 L'opérateur << L'opérateur d'insertion (<<) permet d'envoyer des données sur un flux de sortie. Tous les types de base du C++ et la classe string peuvent être utilisés. int n = 10; cout << n; char *ptr = "bonjour"; cout << ptr; string str("hello World!"); cout << str << " et peut etre chaine " ; Jean-Louis Pascal page 1/1
3.2 La méthode put() Cette méthode permet de sortir un caractère sur un flux de sortie. char c = 'x'; cout.put(c); // équivalent à cout << c; Cette méthode peut aussi être chaînée. cout.put('s').put('a').put('l').put('u').put('t').put('\n'); 3.3 La méthode write() Cette méthode permet d'envoyer un tableau de caractère sur un flux de sortie de façon brute (ou binaire). char tab[] = 'a', 'b', '\0', 'c' ; cout.write(tab,4); char s[] = "abcdefghijklmnopqrstuvwxyz"; cout.write(s, strlen(s)); // équivalent à cout << s; Cette méthode peut aussi être chaînée. 4. Les entrées 4.1 L'opérateur >> L'opérateur d'extraction (>>) permet d'extraire une donnée d'un flux d'entrée et de la placer dans une variable. Tous les types de base du C++ et la classe string peuvent être utilisés. string nom; int age; cout << "Entrez votre nom "; cin >> nom; cout << "Entrez votre age "; cin >> age; Cet opérateur peut être chaîné. string nom; int age; cout << "Entrez votre nom et votre age "; cin >> nom >> age; En entrées, l'espace, la tabulation et le "retour chariot" sont considérés comme séparateurs, ils ne sont pas lus par l'opérateur >>. Attention avec les chaînes de caractères, il y a un risque de débordement si la chaînes lue est plus longue que la chaîne réceptrice. Exemple char str[50]; cout << "Entrez votre nom " cin >> str; // PROBLEME si l'utilisateur rentre 50 caractères ou plus. Pour remédier à ce problème, il faut utiliser la classe string qui adapte la longueur de la chaîne automatiquement. string str; cout << "Entrez votre nom " cin >> str; 4.2 - Les méthodes get() Les méthodes get() fournissent tous les caractères présents dans le flux d'entrées, séparateurs compris. int n = cin.get(); char c; cin.get(c); char s[10]; cin.get(s,9,'\n'); 4.3 - Les méthodes getline() Les méthodes getline() fonctionnent de la même façon, elles fournissent tous les caractères présents dans le flux d'entrées, séparateurs compris. char str1[10]; Jean-Louis Pascal page 2/2
cin.getline(str1,9); char str2[100]; cin.getline(str2,99,'x'); 4.4 - La fonction getline(istream&, string&) Il existe une fonction (non-membre de istream) qui permet d'extraire des caractères d'un flux d'entrée et de la placer dans une "string". Elle lit une ligne entière jusqu'au caractère '\n' (ou le caractère spécifié par le 3 ème argument) et évite tous les problèmes de débordement causés par des chaînes trop longues. string str; getline(cin,str); getline(cin,str,'x'); 4.5 La méthode read() Cette méthode permet de lire en mode binaire un certain nombre de caractères et de les placer dans un tableau. char tab[100]; cin.read(tab,100); 4.6 Problèmes durant la saisie En plus du problème de débordement (chaîne de caractères trop longue), 2 autres problèmes peuvent survenir Problème de synchronisation entre entrée et sortie int n1, n2; cout << "donnez une valeur pour n1 "; cin >> n1; cout << "merci pour " << n1 << endl; cout << "donnez une valeur pour n2 "; cin >> n2; cout << "merci pour " << n2 << endl; Si l'utilisateur entre 2 nombres sur la même ligne, cela donnera à la console donnez une valeur pour n1 12 15 merci pour 12 donnez une valeur pour n2 merci pour 15 Problème de mauvaise saisie Une mauvaise saisie peut faire échouer la lecture et on risque un "plantage" de programme. int n; do cout << "donnez une valeur "; cin >> n; cout << "le carré de " << n << " est " << n*n << endl; while(n!= 0); Voilà ce que ça peut donner donnez une valeur 3 le carré de 3 est 9 donnez une valeur 4 le carré de 4 est 16 donnez une valeur x le carré de 4 est 16 Jean-Louis Pascal page 3/3
Pour remédier à ces problèmes, il est très fortement conseillé de lire les flux d'entrée ligne par ligne grâce à la fonction getline() (voir 4.4) et ensuite d'extraire les informations des lignes grâce à la classe istringstream (voir 7). 5 Formatage des sorties Des manipulateurs peuvent modifier le format de l'affichage. Le modificateur endl provoque un retour à la ligne. Les modificateurs dec, hex, oct changent la base des nombres entiers, une fois modifiée, la base reste en vigueur jusqu'au prochain modificateur de base. Les modificateurs setw() et setfill() permettent de spécifier la largeur de l'affichage (en nb de caractères) et le caractère de remplissage (espace par défaut). Les manipulateurs (extrait de l'aide de builder C++) Manipulator Use Effect boolalpha io Puts bool values in alphabetic format dec io Converts integers to/from decimal endl o Inserts newline and flushes buffer ends o Inserts end of string character fixed o Puts floating point values in fixed-point flush o Flushes stream buffer hex io Converts integers to/from hexadecimal internal o Adds fill characters at a designated internal point left o Adds fill characters for adjustment to the left noboolalpha io Resets the above noshowbase o Resets the above noshowpoint o Resets the above noshowpos o Resets the above noskipws i Resets the above nounitbuf o Resets the above nouppercase Resets the above oct io Converts to/from octal right o Adds fill characters for adjustment to the right scientific Puts floating point values in scientific setbase(int base) io Sets base for integer (base = 8, 10, 16) setfill(chart c) io Sets fill character for padding setprecision(int n) io Sets precision of floating point values setw(int n) io Sets minimal field width showbase o Generates a prefix indicating the numeric base of an integer showpoint o Always generates a decimal-point for floating-point values showpos o Generates a + sign for non-negative numeric values uppercase o Replaces certain lowercase letters with their uppercase equivalents voir l'exemple suivant et le résultat à l'exécution #include <iomanip> Jean-Louis Pascal page 4/4
int n = 1234; double tab[] = 1.234, 12.3, 4.5, 6.78, 123.456789; cout << "##### Affichage dans differentes bases #####" << endl; cout << "par defaut n = " << n << endl; cout << "en octal n = " << oct << n << endl; cout << "en hexadecimal n = " << hex << n << endl; cout << "en hexadecimal n = " << hex << uppercase << n << endl; cout << "en décimal n = " << dec << n << endl ; cout << endl << "##### Largeurs de champ et remplissage #####" << endl; cout << endl << " *** par defaut ***" << endl; cout << "valeur = " << tab[i] << endl; cout << endl << " *** avec setw() ***" << endl; cout << setw(15) << "valeur = " << setw(10) << tab[i] << endl; cout << endl << " *** avec setw() et setfill() ***" << endl; cout << setw(15) << setfill('+') << "valeur = " << setw(10) << setfill('*') << tab[i] << endl; ##### Affichage dans differentes bases ##### par defaut n = 1234 en octal n = 2322 en hexadecimal n = 4d2 en hexadecimal n = 4D2 en dúcimal n = 1234 ##### Largeurs de champ et remplissage ##### *** par defaut *** valeur = 1.234 valeur = 12.3 valeur = 4.5 valeur = 6.78 valeur = 123.457 *** avec setw() *** valeur = 1.234 valeur = 12.3 valeur = 4.5 valeur = 6.78 valeur = 123.457 *** avec setw() et setfill() *** ++++++valeur = *****1.234 ++++++valeur = ******12.3 ++++++valeur = *******4.5 ++++++valeur = ******6.78 ++++++valeur = ***123.457 Jean-Louis Pascal page 5/5