Pregunta

En el siguiente código de C ++, me di cuenta de que gcount () estaba devolviendo un número mayor de lo que quería, porque getline () consume el carácter de nueva línea final pero no t enviarlo a la secuencia de entrada.

Sin embargo, lo que aún no entiendo es la salida del programa. Para la entrada " Test \ n " ;, ¿por qué obtengo " est \ n " ;? ¿Cómo es que mi error afecta el carácter primero de la cadena en lugar de agregar basura no deseada al final? ¿Y cómo es que la salida del programa está en desacuerdo con el aspecto de la cadena en el depurador (" Prueba \ n " ;, como era de esperar)

#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;
}
¿Fue útil?

Solución

También he duplicado este resultado, Windows Vista, Visual Studio 2005 SP2.

Cuando descubra qué diablos está sucediendo, actualizaré esta publicación.

editar : Bien, ahí vamos. El problema (y los diferentes resultados que las personas están obteniendo) son del \ r. Lo que sucede es que llamas a input.getline y pones el resultado en vecBuffer. La función getline elimina el \ n, pero deja el \ r en su lugar.

Luego transfiere el vecBuffer a una variable de cadena, pero usa la función gcount de input, lo que significa que obtendrá un char demasiado, porque la variable de entrada todavía contiene \ n, y el vecBuffer no.

El resultado resultante es:

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

Entonces, " Prueba " se imprime, seguido de un retorno de carro (vuelve a colocar el cursor al comienzo de la línea), un carácter nulo (sobrescribe la T) y finalmente el \ n, que coloca correctamente el cursor en la nueva línea.

Por lo tanto, debe eliminar el \ r o escribir una función que obtenga la longitud de la cadena directamente de vecBuffer, buscando caracteres nulos.

Otros consejos

He duplicado el problema de Tommy en un sistema Windows XP Pro Service Pack 2 con el código compilado usando Visual Studio 2005 SP2 (en realidad, dice "Versión 8.0.50727.879"), construido como un proyecto de consola.

Si mi archivo test.txt contiene solo " Test " y un CR, el programa escupe " est " (tenga en cuenta el espacio inicial) cuando se ejecute.

Si tuviera que adivinar, diría que esta versión de la implementación tiene un error en el que trata al personaje de la nueva línea de Windows como debería tratarse en Unix (como un " ir al frente de la misma línea "(carácter)), y luego borra el primer carácter para contener parte de la próxima solicitud o algo así.


Actualización: Después de jugar un poco, estoy seguro de que eso es lo que está sucediendo. Si observa strResult en el depurador, verá que se copió sobre un valor decimal 13 al final. Eso es CR, que en Windows-land es '\ n', y en todos los demás es '' volver al comienzo de la línea ''. Si en cambio cambio su constructor para leer:

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

... (para que el CR no se copie), entonces imprime " Test " como esperarías.

Estoy bastante seguro de que la T realmente se escribe y luego se sobrescribe. Ejecutar el mismo programa en una ventana rxvt (cygwin) produce el resultado esperado. Puedes hacer un par de cosas. Si se deshace de ios :: binary en su apertura, se convertirá automáticamente \ r \ n a \ ny las cosas funcionarán como espera.

También puede abrir su archivo de texto en el editor binario haciendo clic en la pequeña flecha hacia abajo en el botón Abrir del cuadro de diálogo Abrir archivo y seleccionando Abrir con ...- > Editor binario. Esto le permitirá mirar su archivo y confirmar que realmente tiene \ r \ ny no solo \ n.

Editar: Redirigí la salida a un archivo y está escribiendo:

Test\r\0\r\n

La razón por la que obtiene \ 0 es que gcount devuelve 6 (se eliminaron 6 caracteres de la secuencia) pero el delimitador final no se copia en el búfer, sino un '\ 0'. cuando está construyendo la cadena, en realidad le está diciendo que incluya el '\ 0'. std :: string no tiene ningún problema con el 0 incrustado y lo genera como se le pide. Aparentemente, algunos shells muestran un carácter en blanco y sobrescriben la T, mientras que otros no hacen nada y el resultado se ve bien, pero probablemente todavía está mal porque tiene el '\ 0' incorporado

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

Cambiar la última línea a esto se detendrá en \ 0 y también obtendrá el resultado esperado.

Probé su código usando Visual Studio 2005 SP2 en Windows XP Pro SP3 (32 bits), y todo funciona bien.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top