Como ler até EOF de cin em C ++

Eu estou codificando um programa que lê dados diretamente da entrada do usuário e queria saber como eu poderia (sem loops) ler todos os dados até EOF da entrada padrão. Eu estava pensando em usar cin.get (input, '\ 0') mas '\ 0' não é realmente o caractere EOF, que apenas lê até EOF ou '\ 0' , o que ocorrer primeiro.

Ou está usando loops a única maneira de fazer isso? Se sim, qual é o melhor caminho?

67

10 Respostas

A única maneira de ler uma quantidade variável de dados de stdin é usando loops. Eu sempre achei que o std :: getline() funciona muito bem:

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

Por padrão, getline() lê até uma nova linha. Você pode especificar um caractere de terminação alternativo, mas o EOF não é um caractere, portanto você não pode simplesmente fazer uma chamada para getline ().

59
adicionado
Algo a ter cuidado aqui é quando você está lendo de arquivos que foram canalizados via stdin, é que isso e a maioria das respostas dadas irá acrescentar um avanço de linha extra no final da sua entrada. Nem todos os arquivos terminam com um avanço de linha, mas cada iteração do loop anexa "std :: endl" ao fluxo. Isso pode não ser um problema na maioria dos casos, mas se a integridade do arquivo for um problema, isso pode voltar a incomodá-lo.
adicionado o autor Zoccadoum, fonte
Esta não deve ser a resposta mais votada. Veja a resposta abaixo do wiki da comunidade. Além disso, talvez veja essa pergunta: stackoverflow.com/questions/3203452/…
adicionado o autor loxaxs, fonte

Você pode fazer isso sem loops explícitos usando iteradores de fluxo. Tenho certeza de que ele usa algum tipo de loop 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
adicionado
Agradável. Quanto a "tenho certeza que ele usa algum tipo de loop internamente" - qualquer solução seria.
adicionado o autor Michael Burr, fonte
Isso parece remover os caracteres de nova linha da entrada, mesmo que ocorram no meio.
adicionado o autor Multisync, fonte

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))
{
   ...
}

recurso

37
adicionado

Depois de pesquisar a solução do KeithB usando std :: istream_iterator , descobri o < code> std: istreambuf_iterator .

Teste o programa para ler toda a entrada canalizada em uma string e, em seguida, escreva-a novamente:

#include 
#include 
#include 

int main()
{
  std::istreambuf_iterator begin(std::cin), end;
  std::string s(begin, end);
  std::cout << s;
}
16
adicionado
Esta provavelmente deve ser a resposta canônica.
adicionado o autor Kerrek SB, fonte
Downvoted. Então, quais são os prós ou contras em comparação com a solução da KeithB? Sim, você está usando um std :: istreambuf_iterator em vez de um std :: istream_iterator , mas para quê?
adicionado o autor Multisync, fonte

Provável mais simples e geralmente eficiente:

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

Se necessário, use o fluxo de outros tipos como std :: ostringstream como buffer em vez do fluxo de saída padrão aqui.

4
adicionado
vocês já sabem, mas podem ser úteis para alguns: std :: ostringstream std_input; std_input << std :: cin.rdbuf (); std :: string s = std_input.str() . você tem toda a entrada em s (tenha cuidado com std :: string se a entrada for muito grande)
adicionado o autor ribamar, fonte

Você pode usar o std :: istream :: getline() ( ou, de preferência, a função versão que funciona na std :: string ) para obter uma linha inteira . Ambos têm versões que permitem especificar o delimitador (caractere de fim de linha). O padrão para a versão da string é '\ n'.

2
adicionado

Nota lateral triste: Eu decidi usar o C ++ IO para ser consistente com o código baseado em boost. A partir das respostas a esta pergunta eu escolhi while (std :: getline (std :: cin, linha)) . Usando g ++ versão 4.5.3 (-O3) no cygwin (mintty), obtive uma taxa de transferência de 2 MB/s. Microsoft Visual C ++ 2010 (/ O2) fez 40 MB/s para o mesmo código.

Depois de reescrever o IO para puro C enquanto (fgets (buf, 100, stdin)) o throughput saltou para 90 MB/s em ambos os compiladores testados. Isso faz diferença para qualquer entrada maior que 10 MB ...

2
adicionado
Não há necessidade de reescrever seu código para C puro, basta adicionar um std :: iOS :: sync_with_stdio (false); antes de seu loop while. cin.tie (NULL); também pode ajudar se você intercalar a leitura e a escrita.
adicionado o autor R D, fonte
while(std::cin) {
//do something
}
1
adicionado
Este é um terrível desastre de resposta, já que é virtualmente garantido que ele resulta em código errado.
adicionado o autor Kerrek SB, fonte

Uma opção é usar um contêiner, por exemplo

std::vector data;

e redirecionar todas as entradas nesta coleção até que EOF seja recebido, ou seja,

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

No entanto, o contêiner usado pode precisar realocar a memória com muita freqüência, ou você terminará com uma exceção std :: bad_alloc quando o sistema ficar sem memória. Para resolver esses problemas, você poderia reservar uma quantia fixa N de elementos e processar essa quantidade de elementos isoladamente, ou seja,

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
adicionado

Espere, estou entendendo você corretamente? Você está usando o cin para entrada de teclado e deseja parar de ler a entrada quando o usuário digita o caractere EOF? Por que o usuário digitaria o caractere EOF? Ou você quis dizer que quer parar de ler um arquivo no EOF?

Se você está realmente tentando usar cin para ler um caractere EOF, então por que não apenas especificar o EOF como delimitador?

// Needed headers: iostream

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

Se você pretende parar de ler um arquivo no EOF, basta usar o getline e especificar novamente o 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
adicionado