Cómo leer hasta EOF desde cin en C ++

Estoy codificando un programa que lee datos directamente de la entrada del usuario y me preguntaba cómo podría (sin bucles) leer todos los datos hasta EOF desde la entrada estándar. Estaba considerando usar cin.get (input, '\ 0') pero '\ 0' no es realmente el carácter EOF, que solo lee hasta EOF o '\ 0' , lo que ocurra primero.

¿O está utilizando los bucles la única manera de hacerlo? Si es así, ¿cuál es la mejor manera?

67

10 Respuestas

La única manera en que puede leer una cantidad variable de datos desde stdin es usando bucles. Siempre he encontrado que la std :: getline() la función funciona muy bien:

std::string line;
while (std::getline(std::cin, line))
{
    std::cout << line << std::endl;
}

Por defecto getline() lee hasta una nueva línea. Puede especificar un carácter de terminación alternativo, pero EOF no es en sí mismo un carácter, por lo que no puede simplemente hacer una llamada a getline ().

59
agregado
Algo de lo que hay que tener cuidado aquí es cuando estás leyendo desde archivos que se han conectado vía stdin, es que esta y la mayoría de las respuestas dadas agregarán un avance de línea adicional al final de tu entrada. No todos los archivos terminan con un avance de línea, pero cada iteración del ciclo agrega "std :: endl" a la transmisión. Esto puede no ser un problema en la mayoría de los casos, pero si la integridad del archivo es un problema, esto puede volver a morderte.
agregado el autor Zoccadoum, fuente
Esta no debería ser la respuesta más votada. Consulte la respuesta wiki de la comunidad a continuación. Además, tal vez vea esta pregunta: stackoverflow.com/questions/3203452/…
agregado el autor loxaxs, fuente

Puede hacerlo sin bucles explícitos mediante el uso de iteradores de flujo. Estoy seguro de que utiliza algún tipo de bucle internamente.

#include 
#include 
#include 
#include 
#include 

int main()
{
// don't skip the whitespace while reading
  std::cin >> std::noskipws;

// use stream iterators to copy the stream to a string
  std::istream_iterator it(std::cin);
  std::istream_iterator end;
  std::string results(it, end);

  std::cout << results;
}
43
agregado
Bonito. En cuanto a "estoy seguro de que utiliza algún tipo de bucle internamente", cualquier solución lo haría.
agregado el autor Michael Burr, fuente
Esto parece eliminar los caracteres de nueva línea de la entrada, incluso si ocurren justo en el medio.
agregado el autor Multisync, fuente

Usando loops:

#include 
using namespace std;
...
// numbers
int n;
while (cin >> n)
{
   ...
}
// lines
string line;
while (getline(cin, line))
{
   ...
}
// characters
char c;
while (cin.get(c))
{
   ...
}

resource

37
agregado

Después de investigar la solución de KeithB usando std :: istream_iterator , descubrí el < code> std: istreambuf_iterator .

Probar el programa para leer toda la entrada canalizada en una cadena y luego escribirla de nuevo:

#include 
#include 
#include 

int main()
{
  std::istreambuf_iterator begin(std::cin), end;
  std::string s(begin, end);
  std::cout << s;
}
16
agregado
Esta debería ser probablemente la respuesta canónica.
agregado el autor Kerrek SB, fuente
Downvoted. ¿Cuáles son los pros o los contras en comparación con la solución de KeithB? Sí, está utilizando un std :: istreambuf_iterator en lugar de un std :: istream_iterator , pero ¿para qué?
agregado el autor Multisync, fuente

Probable más simple y generalmente eficiente:

#include 
int main()
{
    std::cout << std::cin.rdbuf();
}

Si es necesario, use stream de otros tipos como std :: ostringstream como buffer en lugar de flujo de salida estándar aquí.

4
agregado
ustedes ya lo saben, pero puede ser útil para algunos: std :: ostringstream std_input; std_input << std :: cin.rdbuf (); std :: string s = std_input.str() . tiene toda la entrada en s (tenga cuidado con std :: string si la entrada es demasiado grande)
agregado el autor ribamar, fuente

Puede utilizar la std :: istream :: getline() ( o preferiblemente la función que funciona en std :: cadena ) para obtener una línea completa . Ambos tienen versiones que le permiten especificar el delimitador (carácter de fin de línea). El valor predeterminado para la versión de cadena es '\ n'.

2
agregado

Triste nota: decidí usar C ++ IO para ser consistente con el código basado en boost. De las respuestas a esta pregunta elegí while (std :: getline (std :: cin, line)) . Usando g ++ versión 4.5.3 (-O3) en cygwin (mintty) obtuve 2 MB/s de rendimiento. Microsoft Visual C ++ 2010 (/ O2) lo convirtió en 40 MB/s para el mismo código.

Después de reescribir el IO en puro C while (fgets (buf, 100, stdin)) el rendimiento saltó a 90 MB/s en ambos compiladores probados. Eso hace una diferencia para cualquier entrada de más de 10 MB ...

2
agregado
No es necesario volver a escribir el código en C puro, simplemente agregue un std :: iOS :: sync_with_stdio (false); antes de su while-loop. cin.tie (NULL); también puede ayudar si intercalas lectura y escritura.
agregado el autor R D, fuente
while(std::cin) {
//do something
}
1
agregado
Este es un desastre terrible de una respuesta, ya que está prácticamente garantizado que se obtenga un código incorrecto.
agregado el autor Kerrek SB, fuente

Una opción es usar un contenedor, p.

std::vector data;

y redirigir toda la entrada a esta colección hasta que se reciba EOF , es decir

std::copy(std::istream_iterator(std::cin),
    std::istream_iterator(),
    std::back_inserter(data));

Sin embargo, es posible que el contenedor utilizado tenga que reasignar la memoria con demasiada frecuencia o terminará con una excepción std :: bad_alloc cuando el sistema se quede sin memoria. Para resolver estos problemas, puede reservar una cantidad fija N de elementos y procesar esta cantidad de elementos de forma aislada, es decir

data.reserve(N);    
while (/*some condition is met*/)
{
    std::copy_n(std::istream_iterator(std::cin),
        N,
        std::back_inserter(data));

    /* process data */

    data.clear();
}
0
agregado

Espera, ¿te entiendo correctamente? ¿Estás utilizando cin para ingresar el teclado, y quieres dejar de leer la entrada cuando el usuario ingresa el carácter EOF? ¿Por qué el usuario alguna vez ingrese el carácter EOF? ¿O quiso decir que quiere dejar de leer un archivo en el EOF?

Si realmente está tratando de usar cin para leer un carácter EOF, ¿por qué no simplemente especifica el EOF como el delimitador?

// Needed headers: iostream

char buffer[256];
cin.get( buffer, '\x1A' );

Si quiere dejar de leer un archivo en el EOF, simplemente use getline y especifique de nuevo el EOF como delimitador.

// Needed headers: iostream, string, and fstream

string buffer;

    ifstream fin;
    fin.open("test.txt");
    if(fin.is_open()) {
        getline(fin,buffer,'\x1A');

        fin.close();
    }
0
agregado