getline() in C++ cos’è e come funziona

La funzione getline() in C++ è uno strumento fondamentale per leggere intere righe di testo da un flusso di input, inclusi gli spazi bianchi. È particolarmente utile quando si ha bisogno di acquisire frasi complete o dati che possono contenere spazi.

Ecco una guida completa e chiara sulla funzione getline(), pensata per uno studente che non ha alcuna conoscenza pregressa sull’argomento.

Cos’è getline() e a Cosa Serve?

Immagina di voler chiedere all’utente di digitare il titolo di un libro, che potrebbe essere “Il Signore degli Anelli”. Se usassi la semplice istruzione cin >> titolo;, il programma leggerebbe solo “Il” e si fermerebbe al primo spazio. Per leggere l’intera frase, inclusi gli spazi, abbiamo bisogno di getline().

getline() è una funzione che legge caratteri da un flusso di input (come la tastiera, un file o una stringa) e li memorizza in una variabile di tipo std::string (stringa di caratteri). La lettura prosegue finché non incontra un “delimitatore” (un carattere specifico che indica la fine della riga) o la fine del flusso.

Dove Trovo getline()? (Header File)

Per poter utilizzare getline() nel tuo codice C++, devi includere la libreria <string>. A volte, includendo <iostream> (che serve per cin e cout), potresti trovarla già disponibile perché <iostream> potrebbe includere internamente <string>, ma per garantire la portabilità e la chiarezza del codice, è sempre buona pratica includere esplicitamente <string>.

#include <iostream> // Per cin e cout
#include <string>   // Per std::string e getline()

int main() {
    // Il tuo codice userà getline() qui
    return 0;
}

Sintassi di Base e Parametri

La funzione getline() ha due forme principali per l’utilizzo con std::string:

  1. getline(flusso_input, variabile_stringa);

    • flusso_input: L’origine da cui leggere i dati (es. std::cin per la tastiera, o un oggetto ifstream per un file).
    • variabile_stringa: La variabile di tipo std::string in cui verrà memorizzata la riga letta.
    • Delimitatore predefinito: Quando non specifichi un delimitatore, getline() considera il carattere di “nuova riga” ('\n', ovvero quando premi Invio) come segnale di fine riga. Il carattere '\n' viene letto ma non memorizzato nella stringa.

    Esempio:

    #include <iostream>
    #include <string>
    
    int main() {
        std::string titolo;
        std::cout << "Inserisci il titolo del libro: ";
        std::getline(std::cin, titolo); // Legge l'intera riga fino a Invio
        std::cout << "Il titolo inserito è: " << titolo << std::endl;
        return 0;
    }
    

    Output d’esempio:

    Inserisci il titolo del libro: Il Signore degli Anelli
    Il titolo inserito è: Il Signore degli Anelli
    
  2. getline(flusso_input, variabile_stringa, delimitatore);

    • Oltre ai primi due parametri, puoi specificare un terzo parametro: delimitatore.
    • delimitatore: Un carattere che, quando incontrato, indica a getline() di smettere di leggere. Anche in questo caso, il carattere delimitatore viene letto e rimosso dal flusso, ma non viene memorizzato nella variabile_stringa.

    Esempio con delimitatore personalizzato:

    #include <iostream>
    #include <string>
    
    int main() {
        std::string dati;
        std::cout << "Inserisci dei dati separati da un punto e virgola: ";
        std::getline(std::cin, dati, ';'); // Legge fino al carattere ';'
        std::cout << "I dati prima del punto e virgola sono: " << dati << std::endl;
        return 0;
        }
    

    Output d’esempio:

    Inserisci dei dati separati da un punto e virgola: valore1;valore2;valore3
    I dati prima del punto e virgola sono: valore1
    

    In questo esempio, getline() legge solo “valore1” perché si ferma al primo ;. Il ; viene “consumato” dal flusso di input, quindi il prossimo getline() o cin inizierebbe a leggere da “valore2”.

Il Valore di Ritorno di getline()

La funzione getline() restituisce il riferimento al flusso di input stesso (es. std::cin). Questo è molto utile perché i flussi di input possono essere usati in contesti booleani (come nelle condizioni if o while) per verificare se l’operazione di lettura è andata a buon fine.

  • Se la lettura è riuscita (non c’è stato un errore e non si è raggiunta la fine del file/flusso), il flusso viene valutato come true.
  • Se la lettura non è riuscita (es. errore o fine del flusso raggiunta prima del previsto), il flusso viene valutato come false.

Questo permette di scrivere cicli eleganti per leggere tutte le righe di un file:

#include <iostream>
#include <string>
#include <fstream> // Per lavorare con i file

int main() {
std::ifstream file_input("miofile.txt"); // Apre un file per la lettura

if (!file_input.is_open()) {
std::cerr << "Errore: impossibile aprire il file!" << std::endl;
return 1;
}

std::string riga;
// Il ciclo continua finché getline() riesce a leggere una riga
while (std::getline(file_input, riga)) {
std::cout << "Riga letta dal file: " << riga << std::endl;
}

file_input.close(); // Chiude il file
return 0;
}

Problema del Carattere '\n'

Uno degli errori più comuni per i principianti si verifica quando si mescolano le operazioni di input cin >> (per leggere numeri o singole parole) con getline().

Il problema:

Quando usi cin >> per leggere un valore (es. un intero), digiti il numero e poi premi Invio. cin >> legge il numero ma lascia il carattere di nuova riga (‘\n’) nel buffer di input. Se subito dopo chiami getline(), questo getline() legge immediatamente quel ‘\n’ residuo come se fosse una riga vuota, “saltando” l’input che ti aspettavi dall’utente.

Esempio del problema:

#include <iostream>
#include <string>

int main() {
    int eta;
    std::string nome;

    std::cout << "Inserisci la tua età: ";
    std::cin >> eta; // Legge l'età, ma lascia '\n' nel buffer

    std::cout << "Inserisci il tuo nome completo: ";
    std::getline(std::cin, nome); // Legge il '\n' lasciato da cin >> eta; e la stringa nome rimane vuota

    std::cout << "Età: " << eta << std::endl;
    std::cout << "Nome: " << nome << std::endl;
    return 0;
}

Se esegui questo codice, dopo aver inserito l’età, la richiesta del nome potrebbe apparire e scomparire immediatamente, e la variabile nome risulterà vuota.

La soluzione:

Per risolvere questo problema, devi “pulire” il buffer di input da quel carattere ‘\n’ residuo prima di chiamare getline(). Ci sono due modi comuni:

  1. Usare std::cin >> std::ws: std::ws è un manipolatore di flusso che estrae e scarta tutti gli spazi bianchi (inclusi i newline) dal flusso di input.

    #include <iostream>
    #include <string>
    
    int main() {
        int eta;
        std::string nome;
    
        std::cout << "Inserisci la tua età: ";
        std::cin >> eta;
    
        // Soluzione 1: Usare std::ws
        std::cout << "Inserisci il tuo nome completo: ";
        std::getline(std::cin >> std::ws, nome); // std::ws pulisce il buffer prima di getline()
    
        std::cout << "Età: " << eta << std::endl;
        std::cout << "Nome: " << nome << std::endl;
        return 0;
  2. Usare std::cin.ignore(): Questa funzione permette di scartare un certo numero di caratteri o scartare caratteri fino a un certo delimitatore. Per pulire il newline residuo, puoi usarla così:

    C++

    #include <iostream>
    #include <string>
    #include <limits> // Per std::numeric_limits
    
    int main() {
        int eta;
        std::string nome;
    
        std::cout << "Inserisci la tua età: ";
        std::cin >> eta;
    
        // Soluzione 2: Usare std::cin.ignore()
        // Scarta tutti i caratteri fino al prossimo newline, inclusi spazi bianchi.
        // numeric_limits<streamsize>::max() indica di scartare un numero massimo di caratteri
        // Il secondo parametro è il delimitatore da scartare
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    
        std::cout << "Inserisci il tuo nome completo: ";
        std::getline(std::cin, nome);
    
        std::cout << "Età: " << eta << std::endl;
        std::cout << "Nome: " << nome << std::endl;
        return 0;
    }
    

Riepilogo

  • Scopo: Leggere intere righe di testo (anche con spazi) da un input.
  • Libreria: Include <string>.
  • Sintassi base: std::getline(flusso_input, variabile_stringa);
  • Delimitatore personalizzato: std::getline(flusso_input, variabile_stringa, delimitatore_carattere);
  • Valore di ritorno: Restituisce il flusso di input, utile per verificare il successo dell’operazione (es. in cicli while).
  • Problema comune: Mescolare cin >> con getline() può causare la lettura di righe vuote.
  • Soluzione al problema: Utilizza std::cin >> std::ws o std::cin.ignore() prima di getline() per pulire il buffer di input.

Con queste informazioni, dovresti essere in grado di usare getline() in modo efficace e chiaro nei tuoi programmi C++!