Problema con getline(?)

di il
14 risposte

Problema con getline(?)

Ciao a tutti, mi sono appena iscritto per chiedere il vostro aiuto.
Sto imparando il c++ e sto facendo alcune esercitazioni relative alla gestione dei file. In pratica vorrei scrivere un programma che prende in input dei dati di n studenti (nome, matricola e voto) e li inserisce in un file che può essere poi utilizzato in seguito.
Vi posto il codice che ho scritto:
#include<iostream>
#include<string>
#include<fstream>
using namespace std;



int main(){
    string nome;
    string matricola;
    int voto,n;
    fstream file;
    
    file.open("elenco_studenti.txt"); 
    if(!file){
              cout<<"Impossibile aprire il file";
              return 1;
    }
    cout<<"Quanti studenti vuoi inserire? ";
    cin>>n;
    for(int i=0;i<n;i++){
            cout<<"Inserisci i dati del "<<i+1<<" studente:"<<endl;
            cout<<"Nome e cognome: ";
            getline(cin,nome);
            file<<nome<<";";
            cout<<"Matricola: ";
            getline(cin,matricola);
            file<<matricola<<";";
            cout<<"Voto esame: ";
            cin>>voto;
            file<<voto<<";";
                    
    }
    
    return 0;
    }
il codice non è commentato perchè si tratta di poche righe e credo che sia di immediata comprensione. Innanzitutto vorrei sapere se ho utilizzato getline in modo appropriato. L'ho usato perchè ho la necessità di salvare nella variabile "nome" anche lo spazio tra nome e cognome e dunque non ho potuto usare un semplice "cin>>nome".Analogo discorso per la matricola. Ad ogni modo a runtime ho il seguente problema: dopo aver inserito n (numero di studenti da inserire nel file) il programma non mi fa inserire il nome, ma esclusivamente matricola e voto. Vi posto anche un esempio d'uso:
Quanti studenti vuoi inserire? 3
Inserisci i dati del 1o studente:
Nome e cognome: Matricola: n12345
Voto:22
Inserisci i dati del 2o studente:
Nome e cognome: Matricola: n67890
Voto:26
e così via per tutti gli n studenti.
Non ho problemi invece con la matricola, che è comunque di tipo string e per la quale ho utilizzato allo stesso modo la getline;
Infine vi posto il file modificato dal programma dopo l'esecuzione:
;n12345;22;;n67890;26;;n34567;30;
Vi prego di non infierire perchè sono un novellino!!!
Grazie a tutti in anticipo

14 Risposte

  • Re: Problema con getline(?)

    Il tuo problema è risolto in vari modi qui http://stackoverflow.com/questions/5739937/using-getlinecin-s-after-cin
    In sostanza la cin >> n non rimuove l'invio che dai, che quindi ti viene considerato dalla successiva getline().
    Perchè non usi ovunque getline()?
  • Re: Problema con getline(?)

    candaluar ha scritto:


    Il tuo problema è risolto in vari modi qui http://stackoverflow.com/questions/5739937/using-getlinecin-s-after-cin
    In sostanza la cin >> n non rimuove l'invio che dai, che quindi ti viene considerato dalla successiva getline().
    Perchè non usi ovunque getline()?
    Grazie mille!!
    Ho risolto aggiungendo cin.ignore() nel ciclo for, subito prima di getline. Secondo te è valida come soluzione oppure sa troppo di "rattoppo"?
    E cosa intendi esattamente con "perchè non usi ovunque getline()"? Cioè sostituire anche "cin>>n" e "cin>>voto" con getline? Va scritta sempre allo stesso modo visto che non sono string ma int? Grazie in anticipo
  • Re: Problema con getline(?)

    Cin.ignore() va bene.
    Per leggere un intero con getline devi passare per una stringa temporanea che poi converti in intero, eventualmente ti fai una funzioncina che fa questo lavoro.
  • Re: Problema con getline(?)

    candaluar ha scritto:


    cin.ignore() va bene.
    Per leggere un intero con getline devi passare per una stringa temporanea che poi converti in intero, eventualmente ti fai una funzioncina che fa questo lavoro.
    mi introduco anch'io per chiedere una cosa: perché "sprecare" tutto questo tempo per fare una getline per un intero, anziché usare direttamente l'oggetto cin?
    l'utilizzo della getline non dovrebbe limitarsi alla lettura di stringhe con spazi?
  • Re: Problema con getline(?)

    La getline svuota il buffer della tastiera anche del newline. Se usi getline per leggere anche l'intero non hai poi bisogno cin.ignore.
    Era un'alternativa.
  • Re: Problema con getline(?)

    candaluar ha scritto:


    Era un'alternativa.
    E da sempre è anche l'unica sensata per evitare i problemi che l'OP lamenta. Per quanto riguarda l'input meglio dimenticarsi degli operatori di estrazione e acquisire i dati come stringa per poi eventualmente parserizzarla.
    Se poi ci si preoccupa delle "prestazioni" occorre tenere presente che il tempo uomo dedicato all'immissione del dato è infinitamente superiore al tempo macchina necessario per il parsering.
  • Re: Problema con getline(?)

    E da sempre è anche l'unica sensata per evitare i problemi che l'OP lamenta. Per quanto riguarda l'input meglio dimenticarsi degli operatori di estrazione e acquisire i dati come stringa per poi eventualmente parserizzarla.
    Shodan, sono d'accordo con te ma non volevo confondere le idee ad una persona che sta imparando il C++.
    Piuttosto volevo dargli degli spunti come la creazione di una funzione per l'inserimento di valori interi, utilizzando internamente getline() (e quindi iniziare a non scrivere tutto nel main!).
    Si tratta di spunti che l'OP può benissimo capire, anche più in là nello studio: da come ha saputo descrivere bene il proprio problema (rispetto ad altri che sanno dire solo "non va") le premesse ci sono tutte .
    Se poi ci si preoccupa delle "prestazioni" occorre tenere presente che il tempo uomo dedicato all'immissione del dato è infinitamente superiore al tempo macchina necessario per il parsering.
    Anche qui sono d'accordo con te: aggiungo che le prestazioni sono la prima preoccupazione dell'aspirante programmatore (non solo maschi ), prima ancora di capire come scambiare fra loro il contenuto di due variabili, e da discorsi tipo "C++ è più veloce di Java", "Python è lento", "il C è velocissimo" si capisce il grado di preparazione di uno sviluppatore.
  • Re: Problema con getline(?)

    candaluar ha scritto:


    cin.ignore() va bene.
    Per leggere un intero con getline devi passare per una stringa temporanea che poi converti in intero, eventualmente ti fai una funzioncina che fa questo lavoro.
    Grazie e scusami se rispondo soltanto adesso.
    Innanzitutto non riesco a convertire la stringa in int Ho visto un pò un giro e consigliano di usare "atoi" o "stoi" ma non sono riuscito a far funzionare nessuna delle due, se non dichiarando la stringa come "char s[10]" (per esempio).
    La funzione l'avrei pensata così:
    
    void get_int(int &n){
                            string str;
        			cout<<"Quanti studenti vuoi inserire? ";
        			getline(cin,str);
        			n=atoi(str); 			
           }
    
    e poi nel main l'avrei chiamata con:
    int n;
    get_int(n);
    Ovviamente non funziona a causa di quel "n=atoi(str)" (stessa cosa con "n=stoi(str)"). Sicuramente sono io a non saperli usare e quindi vorrei sapere come farli funzionare.
    Non ho problemi invece se, come ho scritto sopra, dichiaro la stringa come array di char e la leggo con il cin per poi utilizzare atoi. Infatti la funzione, come scritta di seguito, funziona senza problemi:
    void get_int(int &n){
                 char str[10];
                 cout<<"Quanti studenti vuoi inserire? ";
                 cin>>str;
                 n=atoi(str);
                      
          }
  • Re: Problema con getline(?)

    Se lavori con una stringa devi usare stoi() vedi
    Se lavori con un array di char (ovvero con una stringa C) devi usare atoi() come giustamente hai fatto; attenzione però che se uno ti inserisce più di 9 caratteri può avvenire un crash perchè la getline() non conosce la dimensione del buffer (10) e per questo ti consiglio di riprovare sulla strada della stringa, in cui questo fastidio non c'è.
    Una nota: la get_int() non deve stampare "Quanti ...", perchè altrimenti non la puoi riutilizzare per altri inserimenti!
  • Re: Problema con getline(?)

    candaluar ha scritto:


    Se lavori con una stringa devi usare stoi() vedi
    Se lavori con un array di char (ovvero con una stringa C) devi usare atoi() come giustamente hai fatto; attenzione però che se uno ti inserisce più di 9 caratteri può avvenire un crash perchè la getline() non conosce la dimensione del buffer (10) e per questo ti consiglio di riprovare sulla strada della stringa, in cui questo fastidio non c'è.
    Una nota: la get_int() non deve stampare "Quanti ...", perchè altrimenti non la puoi riutilizzare per altri inserimenti!
    Effettivamente la domanda "Quanti ecc..." deve andare fuori dalla funzione. Ma ancora non riesco a farlo funzionare... se provo ad inserire stoi al posto di atoi (ovviamente con str di tipo string e non array di char), al momento della compilazione, alla riga "n=stoi(str);" mi da l'errore "stoi undeclared". Ho incluso le librerie <iostream> e <string> e la riga "using namespace std;"... devo forse includerne qualche altra
  • Re: Problema con getline(?)

    Dai un'occhiata agli esempi presenti nel link che ti ho postato
  • Re: Problema con getline(?)

    candaluar ha scritto:


    Dai un'occhiata agli esempi presenti nel link che ti ho postato
    Li avevo già guardati, grazie. Ma anche facendo il copia/incolla degli stessi esempi mi dava lo stesso errore ("stoi undeclared")... Quindi documentandomi ho scoperto che la funzione stoi è stata introdotta con lo standard C++11 e dopo aver modificato opportunamente le impostazioni del compilatore è andato tutto liscio!!! Quindi direi che il caso è risolto
    Volevo approfittare per chiedere un'altra cosa senza aprire un nuovo topic:
    Facendo sempre riferimento al codice postato nel mio primo messaggio, il programma ad ogni esecuzione sovrascrive nel file i dati che aveva salvato nell'esecuzione precedente. Come posso fare per far in modo che il programma non sovrascriva quello che c'è nel file ma semplicemente metta i nuovi dati in coda? Spero di essere stato abbastanza chiaro
  • Re: Problema con getline(?)

    Dallo stesso sito del link cerca la open di ofstream, vedrai che c'é un mode che puoi settare ad append...
  • Re: Problema con getline(?)

    candaluar ha scritto:


    Dallo stesso sito del link cerca la open di ofstream, vedrai che c'é un mode che puoi settare ad append...
    Grazie mille!!! Allora ho perfezionato il mio codice ed ora fa proprio quello che volevo. Lo posto di seguito, magari potrebbe essere utile a qualche altro utente. Ricapitolando il programma prende in input i dati di n studenti (nome, matricola e voto) e li memorizza in un file:
    
    #include<iostream>
    #include<string>
    #include<fstream>
    using namespace std;
    
    void get_int(int &n);
    
    int main(){
        string nome;
        string matricola;
        int voto,n;
        ofstream file;  
        file.open("elenco_studenti.txt",fstream::app); 
        if(!file){
                  cout<<"Impossibile aprire il file";
                  return 1;
        }
        cout<<"Quanti studenti vuoi inserire? ";
        get_int(n);
        for(int i=0;i<n;i++){
                cout<<"Inserisci i dati del "<<i+1<<" studente:"<<endl;
                cout<<"Nome e cognome: ";
                getline(cin,nome);
                file<<nome<<";";
                cout<<"Matricola: ";
                getline(cin,matricola);
                file<<matricola<<";";
                cout<<"Voto esame: ";
                get_int(voto);
                file<<voto<<";";
                        
        }
        
        return 0;
        }
        
       void get_int(int &n){
                 string str;
                 getline(cin,str);
                 n=stoi(str);
                      
          }
    
    Ovviamente sono ben accetti eventuali consigli. Grazie ancora!!!
Devi accedere o registrarti per scrivere nel forum
14 risposte