Domanda

Nel seguente codice C ++, mi sono reso conto che gcount () stava restituendo un numero maggiore di quello che volevo, perché getline () consuma il carattere finale della nuova riga ma non t inviarlo al flusso di input.

Ciò che ancora non capisco è l'output del programma. Per input " Test \ n " ;, perché ottengo " est \ n " ;? Come mai il mio errore influenza il primo carattere della stringa piuttosto che aggiungere spazzatura indesiderata alla fine? E come mai l'output del programma è in contrasto con l'aspetto della stringa nel debugger (" Test \ n " come mi aspettavo)?

#include <fstream>
#include <vector>
#include <string>
#include <iostream>

using namespace std;

int main()
{
    const int bufferSize = 1024;
    ifstream input( "test.txt", ios::in | ios::binary );

    vector<char> vecBuffer( bufferSize );
    input.getline( &vecBuffer[0], bufferSize );
    string strResult( vecBuffer.begin(), vecBuffer.begin() + input.gcount() );
    cout << strResult << "\n";

    return 0;
}
È stato utile?

Soluzione

Ho anche duplicato questo risultato, Windows Vista, Visual Studio 2005 SP2.

Quando capirò cosa sta succedendo, aggiornerò questo post.

modifica : Ok, eccoci. Il problema (e i diversi risultati che le persone stanno ottenendo) provengono da \ r. Quello che succede è che chiami input.getline e metti il ??risultato in vecBuffer. La funzione getline elimina \ n, ma lascia \ r in posizione.

Quindi trasferisci vecBuffer su una variabile stringa, ma usi la funzione gcount dall'input, il che significa che otterrai un carattere troppo, perché la variabile di input contiene ancora \ n, e vecBuffer no.

Lo strResult risultante è:

-       strResult   "Test"
        [0] 84 'T'  char
        [1] 101 'e' char
        [2] 115 's' char
        [3] 116 't' char
        [4] 13 '␍'  char
        [5] 0   char

Quindi quindi " Test " viene stampato, seguito da un ritorno a capo (riporta il cursore all'inizio della riga), un carattere null (sovrascrivendo la T) e infine il \ n, che posiziona correttamente il cursore sulla nuova riga.

Quindi devi rimuovere il \ r, o scrivere una funzione che ottiene la lunghezza della stringa direttamente da vecBuffer, controllando la presenza di caratteri null.

Altri suggerimenti

Ho duplicato il problema di Tommy su un sistema Windows XP Pro Service Pack 2 con il codice compilato usando Visual Studio 2005 SP2 (in realtà, dice "Versione 8.0.50727.879"), costruito come un progetto console.

Se il mio file test.txt contiene solo " Test " e un CR, il programma sputa " est " (nota lo spazio iniziale) quando eseguito.

Se dovessi provare a indovinare, direi che questa versione dell'implementazione ha un bug in cui tratta il carattere di nuova riga di Windows come se dovesse essere trattato in Unix (come un " vai all'inizio di la stessa riga " carattere), quindi cancella il primo carattere per contenere parte del prompt successivo o qualcosa del genere.


Aggiornamento: Dopo averci giocato un po ', sono sicuro che è quello che sta succedendo. Se guardi strResult nel debugger, vedrai che alla fine ha copiato un valore decimale 13. Questo è CR, che in Windows-land è '\ n', e ovunque è " torna all'inizio della riga " ;. Se invece cambio il tuo costruttore per leggere:

string strResult (vecBuffer.begin (), vecBuffer.begin () + input.gcount () - 1);

... (in modo che il CR non venga copiato) quindi stampa " Test " come ti aspetteresti.

Sono abbastanza sicuro che la T sia effettivamente scritta e poi sovrascritta. L'esecuzione dello stesso programma in una finestra rxvt (cygwin) produce l'output previsto. Puoi fare un paio di cose. Se ti sbarazzi di ios :: binary alla tua apertura, si convertirà automaticamente da \ r \ n a \ n e le cose funzioneranno come ti aspetti.

Puoi anche aprire il tuo file di testo nell'editor binario facendo clic sulla piccola freccia giù sul pulsante Apri della finestra di dialogo del file aperto e selezionando Apri con ...- > Binary Editor. Questo ti permetterà di guardare il tuo file e confermare che effettivamente ha \ r \ n e non solo \ n.

Modifica Ho reindirizzato l'output su un file e sta scrivendo:

Test\r\0\r\n

Il motivo per cui stai ottenendo lo \ 0 è che gcount restituisce 6 (6 caratteri sono stati rimossi dallo stream) ma il delimitatore finale non è copiato nel buffer, invece è un '\ 0'. quando costruisci la stringa, in realtà le stai dicendo di includere '\ 0'. std :: string non ha problemi con lo 0 incorporato e lo emette come richiesto. Apparentemente alcune shell stanno emettendo un carattere vuoto e sovrascrivendo la T, mentre altri non fanno nulla e l'output sembra a posto, ma probabilmente è ancora sbagliato perché ha lo '\ 0'

incorporato
cout << strResult.c_str() << "\n";

La modifica dell'ultima riga su questa si interromperà su \ 0 e otterrà anche l'output previsto.

Ho testato il tuo codice utilizzando Visual Studio 2005 SP2 su Windows XP Pro SP3 (32 bit) e tutto funziona correttamente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top