Cum se citește până la EOF de la cin în C ++

Sunt codarea unui program care citește date direct de la intrarea utilizatorului și se întreba cum aș putea (fără bucle) să citesc toate datele până la EOF de la intrarea standard. M-am gândit să folosesc cin.get (input, '\ 0') , dar '\ 0' nu este chiar caracterul EOF care citește până la EOF sau < '\ 0' , oricare dintre acestea survine mai întâi.

Sau foloseste buclele singura cale de ao face? Dacă da, care este cel mai bun mod?

67

10 răspunsuri

Singurul mod în care puteți citi o cantitate variabilă de date de la stdin utilizează bucle. Întotdeauna am găsit că std :: getline() funcția funcționează foarte bine:

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

În mod implicit, getline() citește până la o linie nouă. Puteți specifica un caracter alternativ de terminare, dar EOF nu este el însuși un caracter, astfel încât să nu puteți face un simplu apel la getline ().

59
adăugat
Ceva care trebuie să fie atent aici este atunci când citiți din fișiere care au fost piped în via stdin, este faptul că acest lucru și cele mai multe dintre răspunsurile date vor adăuga o alimentare suplimentară linie la sfârșitul dvs. de intrare. Nu toate fișierele se termină cu un feed de linie, dar fiecare iterație a bucla adaugă "std :: endl" la flux. Acest lucru poate să nu fie o problemă în majoritatea cazurilor, dar dacă integritatea fișierelor este o problemă, acest lucru s-ar putea întâmpla să te muște.
adăugat autor Zoccadoum, sursa
Acest lucru nu ar trebui să fie cel mai rău răspuns. Vedeți răspunsul de mai jos al comunității wiki. De asemenea, puteți vedea această întrebare: stackoverflow.com/questions/3203452/…
adăugat autor loxaxs, sursa

Puteți face acest lucru fără bucle explicite prin utilizarea iteratorilor de fluxuri. Sunt sigur că foloseste un fel de buclă intern.

#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
adăugat
Frumos. În ceea ce privește "Sunt sigur că utilizează un fel de buclă în interior" - orice soluție ar fi.
adăugat autor Michael Burr, sursa
Acest lucru pare să elimine caracterele din linia de intrare, chiar dacă acestea apar chiar în mijloc.
adăugat autor Multisync, sursa

Utilizând bucle:

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

resursă

37
adăugat

După ce am cercetat soluția lui KeithB folosind std :: istream_iterator , am descoperit < code> std: istreambuf_iterator .

Testați programul pentru a citi toate intrările de conducte într-un șir, apoi scrie-l din nou:

#include 
#include 
#include 

int main()
{
  std::istreambuf_iterator begin(std::cin), end;
  std::string s(begin, end);
  std::cout << s;
}
16
adăugat
Acesta ar fi probabil răspunsul canonic.
adăugat autor Kerrek SB, sursa
Downvoted. Deci, care sunt argumentele pro sau contra în comparație cu soluția lui KeithB? Da, folosiți un std :: istreambuf_iterator în loc de std :: istream_iterator , dar pentru ce?
adăugat autor Multisync, sursa

Probabil cel mai simplu și în general eficient:

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

Dacă este necesar, utilizați fluxul de alte tipuri ca std :: ostringstream ca tampon în loc de fluxul de ieșire standard aici.

4
adăugat
știți deja, dar poate fi util pentru unii: std :: ostringstream std_input; std_input << std :: cin.rdbuf (); std :: șir s = std_input.str() . aveți toate intrările în s (aveți grijă cu std :: string dacă intrarea este prea mare)
adăugat autor ribamar, sursa

Puteți folosi std :: istream :: getline() ( sau, de preferință, versiunea care funcționează pe std :: string ) pentru a obține o întreagă linie . Ambele au versiuni care vă permit să specificați delimitatorul (caracterul final al liniei). Valoarea implicită pentru versiunea șirului este '\ n'.

2
adăugat

Nota trista: am decis sa folosesc C ++ IO pentru a fi in concordanta cu codul bazat pe boost. Din răspunsurile la această întrebare am ales în timp ce (std :: getline (std :: cin, line)) . Folosind g ++ versiunea 4.5.3 (-O3) în cygwin (mintty) am 2 MB/s de transfer. Microsoft Visual C ++ 2010 (/ O2) a făcut 40 MB/s pentru același cod.

După rescrierea IO la C pur în timp ce (fgets (buf, 100, stdin)) , transferul a crescut la 90 MB/s în ambele compilatoare testate. Asta face diferenta pentru orice intrare mai mare de 10 MB ...

2
adăugat
Nu este nevoie să vă rescrieți codul în C pur, trebuie doar să adăugați un std :: iOS :: sync_with_stdio (false); înaintea ciclului dvs. de timp. cin.tie (NULL); poate ajuta, de asemenea, dacă intercalați citirea și scrierea.
adăugat autor R D, sursa
while(std::cin) {
//do something
}
1
adăugat
Acesta este un dezastru teribil al unui răspuns, deoarece este practic garantat că va duce la un cod greșit.
adăugat autor Kerrek SB, sursa

O opțiune este folosirea unui container, de ex.

std::vector data;

și redirecționați toate datele introduse în această colecție până la primirea EOF , adică

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

Cu toate acestea, containerul utilizat ar putea avea nevoie să reallocalizeze memoria prea des sau veți termina cu o excepție std :: bad_alloc atunci când sistemul dvs. va ieși din memorie. Pentru a rezolva aceste probleme, puteți rezerva o sumă fixă ​​ N a elementelor și puteți procesa aceste cantități de elemente în mod izolat, adică

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
adăugat

Așteaptă, te înțeleg corect? Folosiți cin pentru introducerea tastaturii și doriți să opriți citirea intrărilor când utilizatorul introduce caracterul EOF? De ce ar introduce utilizatorul vreodată caracterul EOF? Sau vrei să spui că vrei să nu mai citești dintr-un dosar la EOF?

Dacă de fapt încercați să utilizați cin pentru a citi un caracter EOF, atunci de ce nu specificați doar EOF ca delimiter?

// Needed headers: iostream

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

Dacă intenționați să opriți citirea dintr-un fișier de la EOF, atunci folosiți linia getline și, din nou, specificați EOF ca delimiter.

// 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
adăugat
iOS dezvoltatori, România — Moldova
iOS dezvoltatori, România — Moldova
21 participanți

Parteneri: ciupacabra.com, @php_ro, @js_ro, @node_ro, @seo_ro Android: @ro_android