104

I am coding a program that reads data directly from user input and was wondering how could I (without loops) read all data until EOF from standard input. I was considering using cin.get( input, '\0' ) but '\0' is not really the EOF character, that just reads until EOF or '\0', whichever comes first.

Or is using loops the only way to do it? If so, what is the best way?

11 Answers 11

100

The only way you can read a variable amount of data from stdin is using loops. I've always found that the std::getline() function works very well:

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

By default getline() reads until a newline. You can specify an alternative termination character, but EOF is not itself a character so you cannot simply make one call to getline().

2
  • 10
    Something to be careful of here is when you're reading from files that have been piped in via stdin, is that this and most of the answers given will append an extra line feed on the end of your input. Not all files end with a line feed, yet each iteration of the loop appends "std::endl" to the stream. This may not be an issue in most cases, but if file integrity is an issue, this may come back to bite you.
    – Zoccadoum
    Commented Mar 29, 2016 at 0:41
  • 3
    This should not be the most upvoted answer. See the below community wiki answer. Also, maybe see this question: stackoverflow.com/questions/3203452/…
    – loxaxs
    Commented Aug 16, 2017 at 10:21
71

Using loops:

#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))
{
   ...
}

resource

58

You can do it without explicit loops by using stream iterators. I'm sure that it uses some kind of loop internally.

#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;
}
2
  • 3
    Nice. As for "I'm sure that it uses some kind of loop internally" - any solution would. Commented Oct 14, 2008 at 17:39
  • This seems to remove newline characters from input, even if they occur right in the middle.
    – Multisync
    Commented Sep 7, 2017 at 8:44
46

After researching KeithB's solution using std::istream_iterator, I discovered the std:istreambuf_iterator.

Test program to read all piped input into a string, then write it out again:

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

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

istreambuf_iterator bypasses a bunch of locale and formatting processing, it's essentially a lower level version of istream_iterator, and for the purpose of reading stdin until EOF with no intermediate processing it's more suitable out of the box.

3
  • 9
    This should probably be the canonical answer.
    – Kerrek SB
    Commented Feb 19, 2017 at 16:43
  • 3
    Downvoted. So what are the pros or cons compared to KeithB's solution? Yes, you are using an std::istreambuf_iterator instead of an std::istream_iterator, but what for?
    – Multisync
    Commented Sep 7, 2017 at 8:49
  • 2
    std::istreambuf_iterator skips whitespace by default and can be faster
    – Sopel
    Commented Nov 18, 2018 at 21:43
7

Probable simplest and generally efficient:

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

If needed, use stream of other types like std::ostringstream as buffer instead of standard output stream here.

1
  • 2
    you guys already know, but may be helpful to some: std::ostringstream std_input; std_input << std::cin.rdbuf(); std::string s = std_input.str() . you have all the input in s (be careful with std::string if the input is too big)
    – ribamar
    Commented Dec 1, 2015 at 17:42
4

Sad side note: I decided to use C++ IO to be consistent with boost based code. From answers to this question I chose while (std::getline(std::cin, line)). Using g++ version 4.5.3 (-O3) in cygwin (mintty) i got 2 MB/s throughput. Microsoft Visual C++ 2010 (/O2) made it 40 MB/s for the same code.

After rewriting the IO to pure C while (fgets(buf, 100, stdin)) the throughput jumped to 90 MB/s in both tested compilers. That makes a difference for any input bigger than 10 MB...

1
  • No need to rewrite your code to pure C, just add a std::ios::sync_with_stdio(false); before your while-loop. cin.tie(NULL); may also help if you interleave reading and writing.
    – R D
    Commented Nov 19, 2017 at 21:52
2

You can use the std::istream::getline() (or preferably the version that works on std::string) function to get an entire line. Both have versions that allow you to specify the delimiter (end of line character). The default for the string version is '\n'.

0
1

Wait, am I understanding you correctly? You're using cin for keyboard input, and you want to stop reading input when the user enters the EOF character? Why would the user ever type in the EOF character? Or did you mean you want to stop reading from a file at the EOF?

If you're actually trying to use cin to read an EOF character, then why not just specify the EOF as the delimiter?

// Needed headers: iostream

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

If you mean to stop reading from a file at the EOF, then just use getline and once again specify the EOF as the 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
while(std::cin) {
 // do something
}
3
  • 11
    This is a terrible disaster of an answer, since it's virtually guaranteed to result in wrong code.
    – Kerrek SB
    Commented Feb 19, 2017 at 16:43
  • @KerrekSB why it's virtually guaranteed to result in wrong code?
    – matusf
    Commented Oct 1, 2018 at 21:55
  • 1
    @MatúšFerech: Because it strongly suggests that // do something does not contain additional checks of return values of I/O operations, and the check it does contain is meaningless.
    – Kerrek SB
    Commented Oct 3, 2018 at 0:51
0

One option is to a use a container, e.g.

std::vector<char> data;

and redirect all input into this collection until EOF is received, i.e.

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

However, the used container might need to reallocate memory too often, or you will end with a std::bad_alloc exception when your system gets out of memory. In order to solve these problems, you could reserve a fixed amount N of elements and process these amount of elements in isolation, i.e.

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

One line for loop:

for( std::string line; std::getline(std::cin, line); std::cout << line << std::endl );

Not the answer you're looking for? Browse other questions tagged or ask your own question.