21

When programming with c-style i/o I sometimes use freopen() to reopen stdin for testing purposes so that I don't have to retype the input over and over. I was wondering if there is an equivalent for c++ i/o streams. Also, I know that I can use pipes to redirect it on the command line/terminal/whateveritis but I was wondering if there was a way to do it inside my code (because as you can see, I'm not very knowledgeable about the cl/t/w).

flight
  • 7,162
  • 4
  • 24
  • 31
  • Can you read the same data twice when you have two file descriptors of the same stream? If not, you can always use multiple instances of std::cin in C++ – Jonas Bötel Mar 10 '11 at 09:28
  • Possible duplicate of [How to redirect cin and cout to files?](http://stackoverflow.com/questions/10150468/how-to-redirect-cin-and-cout-to-files) – Vadzim Jul 21 '16 at 12:56

3 Answers3

43

freopen also works with cin and cout. No need to search for something new.

freopen("input.txt", "r", stdin); // redirects standard input
freopen("output.txt", "w", stdout); // redirects standard output

int x;
cin >> x; // reads from input.txt
cout << x << endl; // writes to output.txt

Edit: From C++ standard 27.3.1:

The object cin controls input from a stream buffer associated with the object stdin, declared in <cstdio>.

So according to the standard, if we redirect stdin it will also redirect cin. Vice versa for cout.

noɥʇʎԀʎzɐɹƆ
  • 9,967
  • 2
  • 50
  • 67
UmmaGumma
  • 5,633
  • 1
  • 31
  • 45
  • No it does not. This program has undefined behavior. – R.. GitHub STOP HELPING ICE Mar 10 '11 at 14:38
  • @R.. I have use it lot of times on visual studio and g++ and I haven't any problems. Could you please explain what exactly is wrong with it? – UmmaGumma Mar 10 '11 at 14:59
  • Just because something works on one implementation does not mean it's valid C++. Last I checked, it was *at best* implementation-defined whether changes to stdio were visible in the corresponding iostream or vice versa, and possibly worse. – R.. GitHub STOP HELPING ICE Mar 10 '11 at 16:31
  • 1
    @R.. from cplusplus.com `cin is an object of class istream that represents the standard input stream. It corresponds to the cstdio stream stdin.` So cin is connected with stdin and if we are redirecting `stdin` we are also redirecting `cin`. Same thing with `cout`. http://www.cplusplus.com/reference/iostream/cin/ – UmmaGumma Mar 11 '11 at 06:39
  • Hmm, this seems to work but _is_ there a way to do it with just c++ style input features? – flight Mar 11 '11 at 10:14
  • @quasiverse I don't think so. Even timus online judge is suggesting to use freopen for testing in C++. http://acm.timus.ru/help.aspx?topic=cpp – UmmaGumma Mar 11 '11 at 10:54
  • @Ashot The cplusplus.com page was slightly ambiguous about it but timus seems pretty conclusive. Thanks. – flight Mar 11 '11 at 10:58
  • @Ashot: In that case, does this preclude a C++ implementation from performing its own buffering, etc. on top of `stdio`? It seems like it does... – R.. GitHub STOP HELPING ICE Mar 11 '11 at 20:32
  • 1
    @R..GitHubSTOPHELPINGICE You can disable this behavior with `std::sync_with_stdio(false);` so then C++ can do it's own buffering. See also [this answer to a related question](https://stackoverflow.com/a/10151286/3809561) for how you can still redirect `std::cout` if you use `std::sync_with_stdio(false)`. – yyny Jul 30 '20 at 13:55
14
#include <iostream>
#include <fstream>

int main() {

  // Read one line from stdin
  std::string line;
  std::getline(std::cin, line);
  std::cout << line << "\n";

  // Read a line from /etc/issue
  std::ifstream issue("/etc/issue");
  std::streambuf* issue_buf = issue.rdbuf();
  std::streambuf* cin_buf = std::cin.rdbuf(issue_buf);
  std::getline(std::cin, line);
  std::cout << line << "\n";

  // Restore sanity and read a line from stdin
  std::cin.rdbuf(cin_buf);
  std::getline(std::cin, line);
  std::cout << line << "\n";
}

http://www.cplusplus.com/reference/iostream/ios/rdbuf/

Robᵩ
  • 163,533
  • 20
  • 239
  • 308
1

This newsgroup posting explores your options.

This is system dependent and the poster didn't indicate the system, but cin.clear() should work. I have tested the attached program on a UNIX system with AT&T version's of iostreams.

#include <iostream.h>
int main()
{
    for(;;) {
        if ( cin.eof() ) {
            cout << "EOF" << endl;
            cin.clear();
        }
        char c ;
        if ( cin.get(c) ) cout.put(c) ;
    }
} 

Yes, that works okay in cfront and TC++. In g++ where the problem first arose an additional action is required:

  cin.clear();
  rewind ( _iob ); // Seems quite out of place, doesn't it?
                   // cfront also accepts but doesn't
                   // require this rewind. 

Though I note that this was in 1991, it should still work. Remember to use the now-standard iostream header, not iostream.h.

(BTW I found that post with the Google search terms "reopen cin c++", second result.)

Let us know how you get on. You could also just use freopen.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055