Menu

getline in C++: leggere una riga intera, l'input saltato e i file

Come std::getline legge una riga intera in una std::string: usarlo con cin, perché restituisce una stringa vuota dopo cin >>, le soluzioni con cin.ignore e std::ws, delimitatori personalizzati e lettura di un file riga per riga fino alla fine.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Leggere una riga intera

cin >> text legge una sola parola: si ferma al primo spazio. Per leggere tutto ciò che l'utente ha digitato fino al tasto Invio, spazi compresi, usa std::getline dall'header <string>:

#include <iostream>
#include <string>

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

Digitando Ada Lovelace viene stampato Hello, Ada Lovelace!. Con std::cin >> name verrebbe stampato Hello, Ada! e Lovelace resterebbe in attesa nell'input.

La firma è:

std::istream& std::getline(std::istream& input, std::string& text);
std::istream& std::getline(std::istream& input, std::string& text, char delim);
  • input è qualsiasi stream di input: std::cin, un file aperto con std::ifstream o una std::istringstream costruita da una stringa.
  • text viene sostituito (non esteso) con i caratteri letti.
  • delim è il carattere che termina la lettura. Il valore predefinito è '\n'. Il delimitatore viene rimosso dallo stream e non viene memorizzato in text.
  • Il valore restituito è lo stream stesso, ed è questo che ti permette di usarlo in una condizione.

Dato che getline funziona allo stesso modo su qualsiasi stream di input, gli esempi eseguibili di questa pagina leggono da una std::istringstream che contiene un testo fisso. Così l'output è prevedibile senza dover digitare nulla. Per leggere invece dalla tastiera, sostituisci la variabile dello stream con std::cin.

Output:

[Ada Lovelace]
[Alan Turing]

Le parentesi quadre mostrano che l'a capo non fa parte di nessuna delle due stringhe.

getline dopo cin >> restituisce una stringa vuota

È il problema più comune con getline. Leggi un numero con >>, poi una riga con getline, e il getline sembra venire saltato:

Output:

age: 30
city: []

input >> age legge i caratteri 30 e si ferma al primo carattere che non può far parte di un numero, l'a capo. Quell'a capo resta nello stream. getline legge poi fino all'a capo successivo, ne trova uno subito e restituisce una stringa vuota. Con std::cin l'effetto è che il programma non si ferma mai ad aspettare la seconda risposta.

Ci sono due soluzioni standard. Entrambe vanno tra il >> e il getline.

Soluzione 1: scarta il resto della riga con ignore.

Output:

age: 30
city: [Paris]

ignore(n, '\n') butta via caratteri finché non ha rimosso un a capo oppure n caratteri, a seconda di cosa arriva prima. Passare il più grande std::streamsize possibile significa "fino all'a capo, per quanto lontano sia". Rimuove anche tutto ciò che l'utente ha digitato dopo il numero sulla stessa riga, come spazi finali. Con la tastiera la riga è std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');, e richiede #include <limits>.

Un semplice std::cin.ignore() scarta esattamente un carattere. Funziona quando l'a capo segue direttamente il numero, e fallisce non appena c'è uno spazio prima.

Soluzione 2: salta gli spazi iniziali con std::ws.

Output:

age: 30
city: [Paris]

std::ws è un manipolatore che consuma tutti gli spazi bianchi (spazi, tabulazioni, a capo) nella posizione corrente. input >> std::ws restituisce lo stream, quindi può essere passato direttamente a getline. Salta anche le righe vuote e gli spazi iniziali, il che è comodo per nomi e città ma sbagliato quando gli spazi iniziali o una riga vuota sono input significativi. In quel caso usa ignore.

Leggere fino alla fine dell'input

getline restituisce lo stream, e uno stream diventa false quando una lettura fallisce. Quando non ci sono più righe, getline fallisce, quindi un ciclo while attorno a esso legge ogni riga e si ferma alla fine:

Output:

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

Due dettagli di quell'output:

  • Una riga vuota è comunque una lettura riuscita. Produce una stringa vuota e il ciclo continua. Solo il raggiungimento della fine dell'input lo ferma.
  • L'ultima riga non ha bisogno di un a capo finale. Se il testo terminasse con milk 2 senza \n, getline la restituirebbe comunque, e la chiamata successiva fallirebbe.

Con std::cin, lo stesso ciclo legge finché l'input non termina. Questo succede quando l'input viene passato da un file (./program < data.txt), oppure quando l'utente preme Ctrl+D su macOS e Linux, o Ctrl+Z e poi Invio su Windows.

Evita lo schema while (!input.eof()) { std::getline(input, line); ... }. eof() diventa vero solo dopo che una lettura ha già raggiunto la fine, quindi il corpo viene eseguito una volta in più con una lettura fallita e una line vecchia. Metti invece la chiamata a getline nella condizione.

Leggere un file riga per riga

I file usano lo stesso ciclo. Apri il file con std::ifstream da <fstream>, controlla che si sia aperto e leggi:

Output:

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

if (!file) intercetta un file mancante o un percorso sbagliato prima del ciclo. Senza, il ciclo legge semplicemente zero righe, il che sembra un file vuoto invece di un errore. Il file si chiude automaticamente quando file esce dallo scope alla fine di main.

I file salvati su Windows terminano ogni riga con \r\n. Quando un file del genere viene letto su Linux o macOS, getline rimuove il \n ma lascia il \r, quindi ogni riga termina con un ritorno a capo invisibile che rompe i confronti come line == "done". Rimuovilo dopo la lettura:

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

Usare un delimitatore personalizzato

Il terzo argomento cambia il carattere che termina ogni lettura. Un uso comune è dividere una riga sulle virgole. Leggi prima la riga, poi dividila tramite una std::istringstream:

Output:

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

La virgola viene rimossa dallo stream e non memorizzata, come succede all'a capo nella forma predefinita. Nota che con un delimitatore personalizzato l'a capo è un carattere qualsiasi. Se chiami std::getline(file, field, ',') direttamente su un file di più righe, l'ultimo campo di una riga e il primo della successiva ti arrivano uniti, come in "London\nGrace Hopper". Leggere una riga alla volta e dividere ogni riga separatamente evita il problema. La pagina sugli string stream tratta std::istringstream più nel dettaglio, compresa la conversione di campi come "36" in numeri.

std::getline e cin.getline

Esiste anche una funzione membro con un nome simile:

char buffer[20];
std::cin.getline(buffer, 20);        // funzione membro, array di char a dimensione fissa

std::string text;
std::getline(std::cin, text);        // funzione libera, std::string

cin.getline scrive in un array di char e memorizza al massimo size - 1 caratteri più il terminatore '\0'. Una riga più lunga mette lo stream in uno stato di errore, e ogni lettura successiva viene saltata finché non chiami std::cin.clear(). std::getline con una std::string non ha limiti di lunghezza da gestire. Usalo, a meno che tu non stia lavorando con un'API che richiede un array di char.

Errori comuni

  • Mescolare >> e getline senza eliminare l'a capo. Aggiungi ignore(...) oppure usa std::ws tra i due. La pagina su input e output mostra lo stesso problema con std::cin e come riprendersi quando una lettura numerica fallisce.
  • Chiamare getline(std::cin, number) con un int. getline legge solo in una std::string. Leggi la riga, poi convertila con std::stoi o con una std::istringstream.
  • Ciclare su eof(). Verifica direttamente la chiamata a getline: while (std::getline(input, line)).
  • Dimenticare #include <string>. std::getline per le stringhe è dichiarato in <string>. Alcuni compilatori lo lasciano passare tramite <iostream>, e il codice poi fallisce con un altro compilatore.
  • Non controllare che un file si sia aperto. Un percorso sbagliato fa fallire std::ifstream in silenzio e il ciclo di lettura viene eseguito zero volte.

Domande frequenti

Cosa fa getline in C++?

std::getline(stream, text) legge caratteri da stream nella std::string text finché non incontra un a capo, poi rimuove quell'a capo dallo stream senza memorizzarlo. A differenza di cin >> text, conserva gli spazi, quindi legge una riga intera come un nome completo o una frase.

Perché getline viene saltato dopo cin >> in C++?

cin >> number smette di leggere all'a capo che hai digitato dopo il numero e lascia quell'a capo nel buffer di input. Il getline successivo lo trova subito e restituisce una stringa vuota. Scartalo prima con std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');, oppure chiama std::getline(std::cin >> std::ws, text) per saltare gli spazi iniziali.

Come si usa getline con un delimitatore diverso dall'a capo?

Passa il delimitatore come terzo argomento: std::getline(stream, field, ','). Legge fino alla virgola successiva, memorizza il testo che la precede e scarta la virgola. Gli a capo vengono allora trattati come caratteri normali, quindi di solito si combina con una std::stringstream costruita da una singola riga.

Come si legge un file riga per riga in C++?

Aprilo con std::ifstream file("data.txt"); e cicla con while (std::getline(file, line)) { ... }. getline restituisce lo stream, che diventa false quando non ci sono più righe, quindi il ciclo si ferma alla fine del file.

Qual è la differenza tra cin.getline e getline?

std::getline(std::cin, text) è una funzione libera che legge in una std::string, che cresce per contenere qualsiasi riga. std::cin.getline(buffer, size) è una funzione membro che legge in un array di char di dimensione fissa e fallisce se la riga è più lunga di size - 1 caratteri. Usa std::getline con std::string, a meno che tu non abbia un motivo per usare array grezzi.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA