Come leggere fino a EOF da cin in C ++

Sto codificando un programma che legge i dati direttamente dall’input dell’utente e mi chiedevo come avrei potuto (senza loop) leggere tutti i dati fino a EOF dallo standard input. Stavo pensando di usare cin.get( input, '\0' ) ma '\0' non è in realtà il carattere EOF, che legge solo fino a EOF o '\0' , a seconda di cosa viene prima.

O sta usando i loop l’unico modo per farlo? Se sì, qual è il modo migliore?

L’unico modo per leggere una quantità variabile di dati da stdin è l’utilizzo di cicli. Ho sempre trovato che la funzione std::getline() funziona molto bene:

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

Di default getline () legge fino a una nuova riga. È ansible specificare un carattere di terminazione alternativo, ma EOF non è di per sé un personaggio, quindi non è ansible effettuare una sola chiamata a getline ().

Puoi farlo senza cicli espliciti usando iteratori di streaming. Sono sicuro che usa un qualche tipo di 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; } 

Usare i loop:

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

risorsa

Dopo aver cercato la soluzione di KeithB usando std::istream_iterator , ho scoperto lo std:istreambuf_iterator .

Prova il programma per leggere tutti gli input inviati in una stringa, quindi scriverlo di nuovo:

 #include  #include  #include  int main() { std::istreambuf_iterator begin(std::cin), end; std::string s(begin, end); std::cout << s; } 

Probabile il più semplice e generalmente efficiente:

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

Se necessario, usa lo stream di altri tipi come std::ostringstream come buffer invece del stream di output standard qui.

È ansible utilizzare la funzione std :: istream :: getline () (o preferibilmente la versione che funziona su std :: string ) per ottenere un’intera riga. Entrambi hanno versioni che consentono di specificare il delimitatore (carattere di fine riga). Il valore predefinito per la versione della stringa è ‘\ n’.

Triste nota a margine: ho deciso di usare C ++ IO per essere coerente con il codice basato su boost. Dalle risposte a questa domanda ho scelto while (std::getline(std::cin, line)) . Usando g ++ versione 4.5.3 (-O3) in cygwin (mintty) ho ottenuto un throughput di 2 MB / s. Microsoft Visual C ++ 2010 (/ O2) ha reso 40 MB / s per lo stesso codice.

Dopo aver riscritto l’IO in puro C while (fgets(buf, 100, stdin)) il throughput è passato a 90 MB / s in entrambi i compilatori testati. Questo fa la differenza per qualsiasi input più grande di 10 MB …

 while(std::cin) { // do something } 

Aspetta, ti sto capendo correttamente? Stai utilizzando cin per l’input da tastiera e vuoi interrompere la lettura dell’input quando l’utente inserisce il carattere EOF? Perché l’utente dovrebbe mai digitare il carattere EOF? O volevi dire che vuoi smettere di leggere da un file all’EOF?

Se stai effettivamente cercando di usare cin per leggere un carattere EOF, allora perché non specificare solo l’EOF come delimitatore?

 // Needed headers: iostream char buffer[256]; cin.get( buffer, '\x1A' ); 

Se si intende interrompere la lettura da un file su EOF, utilizzare semplicemente getline e specificare nuovamente EOF come delimitatore.

 // Needed headers: iostream, string, and fstream string buffer; ifstream fin; fin.open("test.txt"); if(fin.is_open()) { getline(fin,buffer,'\x1A'); fin.close(); } 

Un’opzione è quella di usare un contenitore, ad es

 std::vector data; 

e redirect tutti gli input in questa raccolta fino a quando non viene ricevuto EOF , ad es

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

Tuttavia, il contenitore utilizzato potrebbe dover ridistribuire la memoria troppo spesso, oppure terminare con un’eccezione std::bad_alloc quando il sistema esaurisce la memoria. Per risolvere questi problemi, è ansible prenotare una quantità fissa di elementi N ed elaborare queste quantità di elementi in isolamento, ad es

 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(); }