Wie liest man bis EOF von cin in C ++?

Ich programmiere ein Programm, das Daten direkt von Benutzereingaben liest und mich gefragt hat, wie ich (ohne Schleifen) alle Daten bis EOF von der Standardeingabe lesen könnte. Ich erwog, cin.get (input, '\ 0') zu verwenden, aber '0' ist nicht wirklich das EOF-Zeichen, das nur bis EOF oder liest '\ 0' , je nachdem, was zuerst eintritt.

Oder verwenden Sie Schleifen, um das zu erreichen? Wenn ja, was ist der beste Weg?

67

10 Antworten

Die einzige Möglichkeit, eine variable Datenmenge von stdin zu lesen, ist die Verwendung von Schleifen. Ich habe immer gefunden, dass std :: getline() Funktion funktioniert sehr gut:

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

Standardmäßig liest getline() bis zu einem Zeilenumbruch. Sie können ein alternatives Beendigungszeichen angeben, aber EOF ist nicht selbst ein Zeichen, so dass Sie nicht einfach einen Aufruf von getline() tätigen können.

59
hinzugefügt
Etwas, auf das Sie hier achten sollten, ist, wenn Sie von Dateien lesen, die über stdin eingegeben wurden, dass dies und die meisten gegebenen Antworten einen zusätzlichen Zeilenvorschub am Ende Ihrer Eingabe anhängen. Nicht alle Dateien enden mit einem Zeilenvorschub, aber jede Wiederholung der Schleife fügt "std :: endl" an den Stream an. Dies ist in den meisten Fällen kein Problem, aber wenn die Dateiintegrität ein Problem darstellt, kann dies dazu führen, dass Sie wieder beißen.
hinzugefügt der Autor Zoccadoum, Quelle
Dies sollte nicht die am meisten angenommene Antwort sein. Siehe die Community Wiki Antwort. Vielleicht sehen Sie auch diese Frage: stackoverflow.com/questions/3203452/…
hinzugefügt der Autor loxaxs, Quelle

Sie können dies ohne explizite Schleifen tun, indem Sie Stream-Iteratoren verwenden. Ich bin mir sicher, dass es intern eine Art Schleife benutzt.

#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
hinzugefügt
Nett. Wie für "Ich bin sicher, dass es intern eine Art von Schleife verwendet" - jede Lösung würde.
hinzugefügt der Autor Michael Burr, Quelle
Dies scheint Neuzeilenzeichen aus der Eingabe zu entfernen, selbst wenn sie genau in der Mitte auftreten.
hinzugefügt der Autor Multisync, Quelle

Schleifen verwenden:

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

Ressource

37
hinzugefügt

Nachdem ich die Lösung von KeithB mit std :: istream_iterator untersucht hatte, entdeckte ich die < code> std: istreambuf_iterator .

Programm testen, um alle piped Eingabe in eine Zeichenfolge zu lesen, und dann wieder ausschreiben:

#include 
#include 
#include 

int main()
{
  std::istreambuf_iterator begin(std::cin), end;
  std::string s(begin, end);
  std::cout << s;
}
16
hinzugefügt
Dies sollte wahrscheinlich die kanonische Antwort sein.
hinzugefügt der Autor Kerrek SB, Quelle
Downvoted. Was sind die Vor- oder Nachteile im Vergleich zur Lösung von KeithB? Ja, Sie verwenden einen std :: istrebbuf_iterator statt eines std :: istream_iterator , aber wozu?
hinzugefügt der Autor Multisync, Quelle

Wahrscheinlichst einfach und allgemein effizient:

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

Verwenden Sie bei Bedarf andere Stream-Typen wie std :: ostringstream als Puffer anstelle des Standard-Ausgabestreams.

4
hinzugefügt
Ihr wisst schon, aber kann für einige hilfreich sein: std :: ostringstream std_input; std_input << std :: cin.rdbuf (); std :: string s = std_input.str() . Du hast alle Eingaben in s (sei vorsichtig mit std :: string wenn die Eingabe zu groß ist)
hinzugefügt der Autor ribamar, Quelle

Sie können die std :: isorem :: getline() ( oder vorzugsweise die Version, die auf std :: string funktioniert, um eine ganze Zeile zu erhalten . Beide haben Versionen, mit denen Sie das Trennzeichen (Zeilenendezeichen) angeben können. Der Standardwert für die Zeichenfolgenversion ist '\ n'.

2
hinzugefügt

Traurige Randnotiz: Ich entschied mich, C ++ IO zu verwenden, um mit boost-basiertem Code konsistent zu sein. Aus den Antworten auf diese Frage wählte ich while (std :: getline (std :: cin, line)) . Mit g ++ Version 4.5.3 (-O3) in Cygwin (Minty) habe ich 2 MB/s Durchsatz. Microsoft Visual C ++ 2010 (/ O2) hat es 40 MB/s für den gleichen Code gemacht.

Nach dem Umschreiben des IO in reinen C während (fgets (buf, 100, stdin)) sprang der Durchsatz in beiden getesteten Compilern auf 90 MB/s. Das macht einen Unterschied für jeden Eingang größer als 10 MB ...

2
hinzugefügt
Du musst deinen Code nicht in reines C umschreiben, sondern füge einfach einen std :: iOS :: sync_with_stdio (false); vor deiner while-Schleife hinzu. cin.tie (NULL); kann auch helfen, wenn Sie Lesen und Schreiben verschachteln.
hinzugefügt der Autor R D, Quelle
while(std::cin) {
//do something
}
1
hinzugefügt
Dies ist eine schreckliche Katastrophe einer Antwort, da es praktisch garantiert zu falschem Code führt.
hinzugefügt der Autor Kerrek SB, Quelle

Eine Möglichkeit besteht darin, einen Behälter, z.B.

std::vector data;

und redirect alle Eingaben in diese Sammlung, bis EOF empfangen wird, d.h.

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

Der verwendete Container muss jedoch möglicherweise den Speicher zu oft neu zuweisen, oder Sie werden mit einer Ausnahme std :: bad_alloc beendet, wenn das System nicht mehr genügend Arbeitsspeicher zur Verfügung hat. Um diese Probleme zu lösen, könnten Sie reservieren eine feste Menge N von Elementen und verarbeiten diese Menge von Elementen isoliert, d.

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
hinzugefügt

Warte, verstehe ich dich richtig? Sie verwenden cin für die Tastatureingabe und möchten die Eingabe nicht mehr lesen, wenn der Benutzer das EOF-Zeichen eingibt? Warum sollte der Benutzer jemals das EOF-Zeichen eingeben? Oder meintest du, dass du aufhören willst, beim EOF aus einer Datei zu lesen?

Wenn Sie tatsächlich versuchen, cin zu verwenden, um ein EOF-Zeichen zu lesen, warum geben Sie dann nicht einfach das EOF als Trennzeichen an?

// Needed headers: iostream

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

Wenn Sie aufhören wollen, beim EOF von einer Datei zu lesen, dann verwenden Sie einfach getline und geben Sie noch einmal den EOF als Trennzeichen an.

// 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
hinzugefügt