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?
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 ().
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;
}
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))
{
...
}
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;
}
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.
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'.
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 ...
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();
}
while(std::cin) {
// do something
}
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();
}