web-dev-qa-db-fra.com

Comment lire jusqu’à EOF de cin en C ++

Je suis en train de coder un programme qui lit les données directement à partir d'une entrée utilisateur et je me demandais comment puis-je (sans boucles) lire toutes les données jusqu'à ce que EOF à partir d'une entrée standard. J'envisageais d'utiliser cin.get( input, '\0' ) mais '\0' n'est pas vraiment le caractère EOF, qui se lit jusqu'au EOF ou '\0', peu importe lequel vient en premier.

Ou encore, utiliser des boucles est-il le seul moyen de le faire? Si oui, quel est le meilleur moyen?

71
Guille

La seule façon de lire une quantité variable de données à partir de stdin consiste à utiliser des boucles. J'ai toujours trouvé que la fonction std::getline() fonctionnait très bien:

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

Par défaut, getline () lit jusqu'à une nouvelle ligne. Vous pouvez spécifier un autre caractère de terminaison, mais EOF n'est pas lui-même un caractère, vous ne pouvez donc pas simplement appeler getline ().

63
trotterdylan

Vous pouvez le faire sans boucles explicites en utilisant des itérateurs de flux. Je suis sûr qu'il utilise une sorte de boucle en interne.

#include <string>
#include <iostream>
#include <istream>
#include <ostream>
#include <iterator>

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<char> it(std::cin);
  std::istream_iterator<char> end;
  std::string results(it, end);

  std::cout << results;
}
47
KeithB

Utiliser des boucles:

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

ressource

41
Degvik

Après avoir recherché la solution de KeithB avec std::istream_iterator, J’ai découvert le std:istreambuf_iterator .

Programme de test pour lire toutes les entrées raccordées dans une chaîne, puis réécrivez-la:

#include <iostream>
#include <iterator>
#include <string>

int main()
{
  std::istreambuf_iterator<char> begin(std::cin), end;
  std::string s(begin, end);
  std::cout << s;
}
22
Richard Smith

Probablement simple et généralement efficace:

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

Si nécessaire, utilisez le flux d’autres types comme std::ostringstream comme tampon au lieu du flux de sortie standard ici.

5
FrankHB

Vous pouvez utiliser la fonction std :: istream :: getline () (ou de préférence la fonction la version qui fonctionne sur std :: string ) pour obtenir une ligne entière. Les deux versions ont des versions vous permettant de spécifier le délimiteur (caractère de fin de ligne). La valeur par défaut pour la version de chaîne est '\ n'.

2
luke

Note latérale triste: j'ai décidé d'utiliser C++ IO pour être cohérent avec le code basé sur le boost. Depuis les réponses à cette question, j'ai choisi while (std::getline(std::cin, line)).). En utilisant g ++ version 4.5.3 (- O3) en cygwin (menthe), j’ai obtenu un débit de 2 Mo/s. Microsoft Visual C++ 2010 (/ O2) lui donnait 40 Mo/s pour le même code.

Après avoir réécrit le IO en C pur while (fgets(buf, 100, stdin))] _, le débit a bondi à 90 Mo/s dans les deux compilateurs testés). Cela fait une différence pour toute entrée supérieure à 10 Mo ...

2
liborm

Attends, je te comprends bien? Vous utilisez cin pour la saisie au clavier et vous souhaitez arrêter la lecture lorsque l'utilisateur saisit le caractère EOF? Pourquoi l'utilisateur taperait-il jamais = EOF = caractère? Ou vouliez-vous dire que vous voulez arrêter de lire un fichier à l'EOF?

Si vous essayez réellement d'utiliser cin pour lire un caractère EOF, pourquoi ne pas simplement spécifier le EOF comme délimiteur?)?

// Needed headers: iostream

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

Si vous souhaitez arrêter de lire un fichier au niveau de l'EOF, utilisez simplement getline et indiquez à nouveau le EOF comme délimiteur.

// 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
derpface
while(std::cin) {
 // do something
}
0
Bryan

Une option consiste à utiliser un conteneur, par ex.

std::vector<char> data;

et redirect toutes les entrées dans cette collection jusqu'à ce que EOF soit reçu, c'est-à-dire.

std::copy(std::istream_iterator<char>(std::cin),
    std::istream_iterator<char>(),
    std::back_inserter(data));

Cependant, le conteneur utilisé peut avoir besoin de réaffecter de la mémoire trop souvent, ou vous allez vous retrouver avec un std::bad_alloc exception lorsque votre système manque de mémoire. Afin de résoudre ces problèmes, vous pouvez réserver un montant fixe N d’éléments et traiter séparément ces éléments, c.-à-d.

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

    /* process data */

    data.clear();
}
0
0xbadf00d