Menu

getline en C++ : lire une ligne entière, corriger la saisie sautée, lire un fichier

Comment std::getline lit une ligne complète dans un std::string : l'utiliser avec cin, pourquoi il renvoie une chaîne vide après cin >>, les solutions avec cin.ignore et std::ws, les délimiteurs personnalisés et la lecture d'un fichier ligne par ligne jusqu'à la fin.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Lire une ligne entière

cin >> text lit un seul mot : il s'arrête au premier espace. Pour lire tout ce que l'utilisateur a tapé jusqu'à la touche Entrée, espaces compris, utilisez std::getline, déclaré dans l'en-tête <string> :

#include <iostream>
#include <string>

int main() {
    std::string name;
    std::cout << "Full name: ";
    std::getline(std::cin, name);
    std::cout << "Hello, " << name << "!\n";
}

Si vous tapez Ada Lovelace, le programme affiche Hello, Ada Lovelace!. Avec std::cin >> name, il afficherait Hello, Ada! et laisserait Lovelace en attente dans l'entrée.

La signature est la suivante :

std::istream& std::getline(std::istream& input, std::string& text);
std::istream& std::getline(std::istream& input, std::string& text, char delim);
  • input est n'importe quel flux d'entrée : std::cin, un fichier ouvert avec std::ifstream, ou un std::istringstream construit à partir d'une chaîne.
  • text est remplacé (et non complété) par les caractères lus.
  • delim est le caractère qui termine la lecture. Sa valeur par défaut est '\n'. Le délimiteur est retiré du flux et n'est pas stocké dans text.
  • La valeur de retour est le flux lui-même, ce qui permet de le tester dans une condition.

Comme getline fonctionne de la même façon sur tous les flux d'entrée, les exemples exécutables de cette page lisent depuis un std::istringstream contenant un texte fixe. La sortie est ainsi prévisible sans rien taper. Pour lire au clavier, remplacez la variable de flux par std::cin.

Sortie :

[Ada Lovelace]
[Alan Turing]

Les crochets montrent que le saut de ligne ne fait partie d'aucune des deux chaînes.

getline après cin >> renvoie une chaîne vide

C'est le problème le plus courant avec getline. Vous lisez un nombre avec >>, puis une ligne avec getline, et le getline semble sauté :

Sortie :

age: 30
city: []

input >> age lit les caractères 30 et s'arrête au premier caractère qui ne peut pas faire partie d'un nombre, le saut de ligne. Ce saut de ligne reste dans le flux. getline lit ensuite jusqu'au saut de ligne suivant, en trouve un immédiatement et renvoie une chaîne vide. Avec std::cin, le résultat est que le programme ne s'arrête jamais pour attendre la deuxième réponse.

Il existe deux corrections classiques. Les deux se placent entre le >> et le getline.

Correction 1 : éliminer le reste de la ligne avec ignore.

Sortie :

age: 30
city: [Paris]

ignore(n, '\n') jette des caractères jusqu'à avoir retiré un saut de ligne ou n caractères, selon ce qui arrive en premier. Passer le plus grand std::streamsize possible signifie « jusqu'au saut de ligne, aussi loin soit-il ». Cela retire aussi tout ce que l'utilisateur a tapé après le nombre sur la même ligne, comme des espaces en fin de ligne. Au clavier, la ligne est std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');, et elle nécessite #include <limits>.

Un simple std::cin.ignore() élimine exactement un caractère. Il fonctionne quand le saut de ligne suit directement le nombre, et échoue dès qu'il y a un espace avant.

Correction 2 : sauter les blancs initiaux avec std::ws.

Sortie :

age: 30
city: [Paris]

std::ws est un manipulateur qui consomme tous les blancs (espaces, tabulations, sauts de ligne) à la position courante. input >> std::ws renvoie le flux, qui peut donc être passé directement à getline. Il saute aussi les lignes vides et les espaces en début de ligne, ce qui est pratique pour des noms et des villes mais incorrect quand des espaces initiaux ou une ligne vide sont des saisies qui comptent. Dans ce cas, utilisez ignore.

Lire jusqu'à la fin de l'entrée

getline renvoie le flux, et un flux se convertit en false dès qu'une lecture échoue. Quand il n'y a plus de lignes, getline échoue, donc une boucle while autour de lui lit chaque ligne et s'arrête à la fin :

Sortie :

1: [apples 3]
2: [bread 1]
3: []
4: [milk 2]
read 4 lines

Deux détails dans cette sortie :

  • Une ligne vide reste une lecture réussie. Elle donne une chaîne vide et la boucle continue. Seule la fin de l'entrée l'arrête.
  • La dernière ligne n'a pas besoin d'un saut de ligne final. Si le texte se terminait par milk 2 sans \n, getline la renverrait quand même, et l'appel suivant échouerait.

Avec std::cin, la même boucle lit jusqu'à la fin de l'entrée. Cela arrive quand l'entrée est redirigée depuis un fichier (./program < data.txt), ou quand l'utilisateur appuie sur Ctrl+D sous macOS et Linux, ou sur Ctrl+Z puis Entrée sous Windows.

Évitez la forme while (!input.eof()) { std::getline(input, line); ... }. eof() ne devient vrai qu'après qu'une lecture a déjà atteint la fin, donc le corps s'exécute une fois de trop avec une lecture ratée et un line périmé. Placez plutôt l'appel à getline dans la condition.

Lire un fichier ligne par ligne

Les fichiers utilisent la même boucle. Ouvrez le fichier avec std::ifstream, déclaré dans <fstream>, vérifiez qu'il est bien ouvert, puis lisez :

Sortie :

1. Ada 92
2. Grace 88
3. Alan 95

if (!file) détecte un fichier absent ou un mauvais chemin avant la boucle. Sans ce test, la boucle lit simplement zéro ligne, ce qui ressemble à un fichier vide plutôt qu'à une erreur. Le fichier se ferme automatiquement quand file sort de portée à la fin de main.

Les fichiers enregistrés sous Windows terminent chaque ligne par \r\n. Quand un tel fichier est lu sous Linux ou macOS, getline retire le \n mais garde le \r, si bien que chaque ligne se termine par un retour chariot invisible qui fait échouer des comparaisons comme line == "done". Retirez-le après la lecture :

if (!line.empty() && line.back() == '\r') {
    line.pop_back();
}

Utiliser un délimiteur personnalisé

Le troisième argument change le caractère qui termine chaque lecture. Un usage courant consiste à découper une ligne selon les virgules. Lisez d'abord la ligne, puis découpez-la à l'aide d'un std::istringstream :

Sortie :

fields: 3
[Ada Lovelace]
[36]
[London]

La virgule est retirée du flux et n'est pas stockée, comme le saut de ligne dans la forme par défaut. Notez qu'avec un délimiteur personnalisé, le saut de ligne devient un caractère ordinaire. Si vous appelez std::getline(file, field, ',') directement sur un fichier de plusieurs lignes, le dernier champ d'une ligne et le premier champ de la suivante reviennent collés ensemble, comme dans "London\nGrace Hopper". Lire une ligne à la fois et découper chaque ligne séparément évite ce problème. La page sur les flux de chaînes présente std::istringstream plus en détail, y compris la conversion de champs comme "36" en nombres.

std::getline ou cin.getline

Il existe aussi une fonction membre au nom proche :

char buffer[20];
std::cin.getline(buffer, 20);        // fonction membre, tableau de char de taille fixe

std::string text;
std::getline(std::cin, text);        // fonction libre, std::string

cin.getline écrit dans un tableau de char et stocke au plus size - 1 caractères plus le '\0' final. Une ligne plus longue met le flux en état d'échec, et toutes les lectures suivantes sont ignorées jusqu'à ce que vous appeliez std::cin.clear(). std::getline avec un std::string n'a aucune limite de longueur à gérer. Utilisez-le, sauf si vous travaillez avec une API qui exige un tableau de char.

Erreurs courantes

  • Mélanger >> et getline sans éliminer le saut de ligne. Ajoutez ignore(...) ou utilisez std::ws entre les deux. La page sur les entrées et sorties montre le même problème avec std::cin et comment se rattraper quand une lecture numérique échoue.
  • Appeler getline(std::cin, number) avec un int. getline ne lit que dans un std::string. Lisez la ligne, puis convertissez-la avec std::stoi ou un std::istringstream.
  • Boucler sur eof(). Testez l'appel à getline lui-même : while (std::getline(input, line)).
  • Oublier #include <string>. Le std::getline des chaînes est déclaré dans <string>. Certains compilateurs le laissent passer via <iostream>, et le code échoue ensuite avec un autre compilateur.
  • Ne pas vérifier qu'un fichier est ouvert. Un mauvais chemin fait échouer std::ifstream sans bruit, et la boucle de lecture s'exécute zéro fois.

Questions fréquentes

Que fait getline en C++ ?

std::getline(stream, text) lit des caractères de stream dans le std::string text jusqu'à rencontrer un saut de ligne, puis retire ce saut de ligne du flux sans le stocker. Contrairement à cin >> text, il conserve les espaces, donc il lit une ligne entière, comme un nom complet ou une phrase.

Pourquoi getline est-il sauté après cin >> en C++ ?

cin >> number s'arrête au saut de ligne que vous avez tapé après le nombre et laisse ce saut de ligne dans le tampon d'entrée. Le getline suivant le trouve aussitôt et renvoie une chaîne vide. Éliminez-le d'abord avec std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');, ou appelez std::getline(std::cin >> std::ws, text) pour sauter les blancs en début de saisie.

Comment utiliser getline avec un autre délimiteur que le saut de ligne ?

Passez le délimiteur en troisième argument : std::getline(stream, field, ','). Il lit jusqu'à la virgule suivante, stocke le texte qui la précède et élimine la virgule. Les sauts de ligne deviennent alors des caractères ordinaires, c'est pourquoi on combine en général cette forme avec un std::stringstream construit à partir d'une seule ligne.

Comment lire un fichier ligne par ligne en C++ ?

Ouvrez-le avec std::ifstream file("data.txt"); et bouclez avec while (std::getline(file, line)) { ... }. getline renvoie le flux, qui se convertit en false quand il n'y a plus de lignes, donc la boucle s'arrête à la fin du fichier.

Quelle est la différence entre cin.getline et getline ?

std::getline(std::cin, text) est une fonction libre qui lit dans un std::string, lequel s'agrandit pour contenir n'importe quelle ligne. std::cin.getline(buffer, size) est une fonction membre qui lit dans un tableau de char de taille fixe et échoue si la ligne dépasse size - 1 caractères. Utilisez std::getline avec std::string, sauf si vous avez une raison de passer par des tableaux bruts.

Illustration des langages de programmation de Coddy

Apprendre à coder avec Coddy

COMMENCER