Visualizzazione dei risultati da 1 a 9 su 9
  1. #1

    [C++] Input/Output File di Testo: Problema con numero righe stampate

    Salve,
    ho un problema da risolvere con i file di testo, argomento per me nuovo.
    (Nota: La domanda principale non riguarda i file di testo quindi, se volete potete andare a leggere direttamente alla fine, tenendo presente che commenti e critiche riguardanti il codice scritto qui sotto sono ben accetti. )
    Avendo il file di testo "mediaEsami.txt"

    De Rossi Mario;13240 28 25 0 24
    Caio Mario;15340 28 0 26 24
    Bianchi Antonio;12540 26 20 30 25
    Ferrara Ciro;13124 30 28 0 27

    dove ogni riga è, in generale, del tipo
    nome cognome;n.matricola voto1 voto2 voto3 voto4

    devo scrivere un programma che mi stampi, dato un numero M, tutti i nomi e le matricole degli studenti che hanno avuto una media maggiore o uguale a M.

    So che risolvere con gli array di record (struct) sarebbe più ordinato ma è un argomento non ancora affrontato all'interno del corso. All'infuori di ciò, ogni commento, critica, o spunto che riguarda il codice è ben accetto.

    Il codice che ho scritto funziona ed è questo:
    codice:
    #include <iostream>
    #include <fstream>
    using namespace std;
    #define MAX_LEN 100
    #define MAX_STR 65
    // PROTOTIPI
    void mediaEsami( char nomeFile[] );
    // MAIN
    int main() {
        char nomeFile[MAX_STR];
        double M; // media
    
        cout << "Inserisci il nome del file di input: ";
        cin >> nomeFile;
    
        mediaEsami( nomeFile );
    
        cout << endl;
        system("pause");
        return 0;
    }
    void mediaEsami( char nomeFile[] ) {
        ifstream ifile;
        char nome[MAX_STR];
        int matricola;
        int nEsami, voto;
        int somma = 0, nVoti = 0;
        double M;
    
        ifile.open( nomeFile );
        if ( !ifile ){
        cerr << "Errore. File non trovato.";
        return;
        }
    
        cout << "Inserisci il numero di esami che gli studenti hanno sostenuto: ";
        cin >> nEsami;
    
        cout << "Inserisci un valore M, considerando che verranno stampati a video " <<
                    "gli studenti con media >= M: ";
        cin >> M;
    
        while ( !ifile.eof() ) {
            ifile.getline( nome, MAX_STR, ';' );
            ifile >> matricola;
            somma = 0;  // azzero i contatori ad ogni ripetizione del ciclo esterno
            nVoti = 0;
            for ( int i = 0; i < nEsami; i++ ) {
                ifile >> voto;
                if ( voto != 0 ) {
                    somma += voto;
                    nVoti++;
                }
            }
            if ( ( static_cast<double>(somma) / static_cast<double>( nVoti ) >= M ) )
                cout << nome << " " << matricola << endl;
        }
    
        ifile.close();
    }
    L'output è di questo tipo:
    codice:
    Inserisci il nome del file di input: mediaEsami.txt
    Inserisci il numero di esami che gli studenti hanno sostenuto: 4
    Inserisci un valore M, considerando che verranno stampati a video gli studenti c
    on media >= M: 26
    
    Caio Mario 15340
    
    Ferrara Ciro 13124
    
    Premere un tasto per continuare . . .

    Ciò che non capisco è:
    Tenendo presente che digito "cout << endl;" solo una volta all'interno della procedura void mediaEsami e non faccio nessuna operazione di estrazione se non quella dal file in input,
    Perchè vi sono gli spazi tra i nomi in output?

    Grazie.

  2. #2
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,480
    Succede perché il ritorno a capo che sta alla fine di ogni riga viene aggiunto all'inizio del nome della riga seguente e visualizzato.

    Per evitare il problema, scartalo leggendolo dopo la cout con una

    ifile.getline( nome, MAX_STR, 0x0A );
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  3. #3
    quindi, se ho capito bene, nel ciclo interno (for) l'ultima operazione di estrazione dal file non estrae il carattere di terminazione di riga (<eol> per intenderci) che viene estratto all'iterazionesuccessiva del primo getline, giusto?
    A questo punto mi sorgono spontanee 2 domande:
    1. Il comando ifile.getline( s, n, c ) NON memorizza una [I]riga[\I] nella variabile s, fino al max n caratteri o fino al raggiungimento del carattere c (che viene scartato e saltato), come il nome suggerirebbe, ma tutti gli n caratteri che incontra fino al raggiungimento del carattere c.
    Non si ferma al carattere di terminazione di ruga se lo incontra, vero?
    2. Suppongo che "0x0A" sia un modo per indicare il carattere di terminazione di riga. Di quale codifica fa parte?
    E' uguale sostituirlo in questo tipo di istruzione ad un più canonico '\n' ?
    Se si, cosa cambia in generale?

  4. #4
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,480
    Originariamente inviato da domeniko92
    quindi, se ho capito bene, nel ciclo interno (for) l'ultima operazione di estrazione dal file non estrae il carattere di terminazione di riga (<eol> per intenderci) che viene estratto all'iterazionesuccessiva del primo getline, giusto?
    In Windows la terminazione della linea è CR LF (caratteri 13 10).
    Il CR viene identificato come fine linea e il LF viene lasciato ancora da leggere.

    A questo punto mi sorgono spontanee 2 domande:
    1. Il comando ifile.getline( s, n, c ) NON memorizza una [I]riga[\I] nella variabile s, fino al max n caratteri o fino al raggiungimento del carattere c (che viene scartato e saltato), come il nome suggerirebbe, ma tutti gli n caratteri che incontra fino al raggiungimento del carattere c.
    Non si ferma al carattere di terminazione di ruga se lo incontra, vero?
    Non ho capito questo tuo dubbio. La getline legge fino al carattere c leggendolo ma escludendolo; in ogni caso, non legge più di n caratteri (a prescindere da c).
    Ma il problema non è la getline.

    2. Suppongo che "0x0A" sia un modo per indicare il carattere di terminazione di riga. Di quale codifica fa parte?
    E' uguale sostituirlo in questo tipo di istruzione ad un più canonico '\n' ?
    Se si, cosa cambia in generale?
    Non cambia nulla. La codifica è la classica ASCII e 10 (0x0A in esadecimale) è il valore ASCII di '\n'. E' una mia abitudine ma puoi usare tranquillamente '\n' al posto di 0x0A (o di 10)
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  5. #5
    Non ho capito questo tuo dubbio. La getline legge fino al carattere c leggendolo ma escludendolo; in ogni caso, non legge più di n caratteri (a prescindere da c).
    Ma il problema non è la getline.


    Non avrai capito il dubbio, però me l'hai risolto
    Comunque, mi chiedevo se il getline catturasse solo la riga "corrente" fino al carattere c, o tutti i caratteri che incontra fino al carattere c (in ogni caso non più di n). Credo di aver capito che esegue la seconda operazione (sebbene il nome sembri suggerire la prima!).

    Non cambia nulla. La codifica è la classica ASCII e 10 (0x0A in esadecimale) è il valore ASCII di '\n'. E' una mia abitudine ma puoi usare tranquillamente '\n' al posto di 0x0A (o di 10)

    Grazie per la completezza della risposta

    EDIT: Dato che dobbiamo saltare un solo carattere, esiste qualche comando alternativo? C'è un comando per saltare semplicemente dei caratteri e far posizionare il cursore, per la prossima estrazione, in una successiva posizione?

  6. #6
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,480
    Originariamente inviato da domeniko92
    Comunque, mi chiedevo se il getline catturasse solo la riga "corrente" fino al carattere c, o tutti i caratteri che incontra fino al carattere c (in ogni caso non più di n). Credo di aver capito che esegue la seconda operazione (sebbene il nome sembri suggerire la prima!).
    Scusa ma non comprendo quale sia per te la differenza tra

    solo la riga fino al carattere c

    e

    tutti i caratteri fino al carattere c

    In ogni caso, il carattere c non è obbligatorio ... vedi la documentazione

    http://www.cplusplus.com/reference/i...tream/getline/
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  7. #7
    Mi spiego meglio. Considerando il file di nome (logico) ifile seguente:
    codice:
    De Rossi Mario;13240 28 25 0 24
    Caio Mario;15340 28 0 26 24
    Bianchi Antonio;12540 26 20 30 25
    Ferrara Ciro;13124 30 28 0 27
    il comando ifile.getline( s, 5000, '6' )

    restituisce
    De Rossi Mario;13240 28 25 0 24
    Caio Mario;15340 28 0 2

    e non un carattere nullo, perché non arresta l'operazione di estrazione alla prima riga (da dove parte l'estrazione).

    Giusto?

    Ne approfitto per incollare la domanda del post precedente.
    EDIT: Dato che dobbiamo saltare un solo carattere, esiste qualche comando alternativo? C'è un comando per saltare semplicemente dei caratteri e far posizionare il cursore, per la prossima estrazione, in una successiva posizione?

  8. #8
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,480
    Originariamente inviato da domeniko92
    ... non arresta l'operazione di estrazione alla prima riga (da dove parte l'estrazione).

    Giusto?
    Giusto, dato che in quel modo gli hai "ridefinito" il concetto di "linea", indicando che una linea termina quando c'è un '6'. Impostata con queste premesse, ha letto una linea (e quindi getline va bene).

    Ne approfitto per incollare la domanda del post precedente.
    Potresti scrivere

    codice:
    char skip; ifile.get(skip);
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  9. #9
    Utente bannato
    Registrato dal
    Apr 2012
    Messaggi
    510
    Edit

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.