Department of Engineering

IT Services

Input/Output

As with C, Input/Output is not part of the language, but support is provided by a library. Most programs need to use #include <iostream>. You may also need #include <fstream> for file I/O, #include <iomanip> for greater control over formatting, and #include <sstream> for I/O to and from strings.

Simple I/O

The following illustrates the use of putback() for an input stream. istreams also have an ignore function (is.ignore(5) would ignore the next 5 characters) and a peek() function which looks at the next character without removing it from the stream.

istream& eatwhite(istream& is)
{
char c;
  while(is.get(c)) {
    if (!isspace(c)) {
      is.putback(c);
      break;
    }
    return is;
  }
}

The following illustrates the use of I/O to and from files. Given the name of 2 files on the command line (which are available to main as C-style character arrays), it does a file copy.

void error(string p, string p2="")
{
 cerr<<p << ' ' << p2 << endl;
 std::exit(1);
}

int main (int argc, char* argv[])
{
 if (argc != 3) error("wrong number of arguments");

 std::ifstream from(argv[1]);
 if (!from) error("cannot open input file", string(argv[1]));

 std::ofstream to(argv[2]);
 if (!to) error("cannot open output file", string(argv[2]));
 
 char ch;
 while (from.get(ch)) to.put(ch);
 
 if (!from || !to) error("something strange happened");
}

You can force the screen/file output to be up-to-date by using

cout.flush() or 
cout << flush;

but this isn't usually necessary.

If you want to write or read raw (binary) data (rather than strings that represent numbers) you can use write, read and casts (section 13) to keep the compiler happy. The following program writes 100 random integers into a file then reads them back.

[fontsize=\small,frame=single,formatcom=\color{progcolor}]
#include <iostream>
#include <fstream>
#include <cstdlib>  // to use rand
using namespace std;

int main()
{

 ofstream outfile("myresults",ios::out|ios::binary);
 if (outfile.good() == false) {
   cerr << "Cannot write to 'myresults'" << endl;
   exit(1);
 }

 int num;
 for (int i=0; i<100; i++){
   num=rand();
   outfile.write(reinterpret_cast<const char*>(&num), sizeof(num));
 }
 outfile.close();

 ifstream infile("myresults");
 if (infile.good() == false) {
   cerr << "Cannot open 'myresults'" << endl;
   exit(1);
 }

 int count=0;
 while(infile.read(reinterpret_cast<char*>(&num), sizeof(num))) {
   cout << num << endl;
   count++;
 }
 cout << count << " numbers read in" << endl;
 infile.close();
 return 0; 
}

Formatting

The way that text and numbers are output can be controlled.

#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

int main()
{
  int i=10;
  cout << "i = " << i << " (default)\n" ;
  cout << hex << "i = " << i << " (hex)\n";

  double d = sqrt(7.0);
  cout << "d=sqrt(7.0)=" << d << endl;
  cout.precision(3);
  cout << "After cout.precision(3), d=" << d << endl;

  return 0;
}

There many other routines too, amongst them

cout.setf(ios_base::oct,ios_base::basefield); // set base to 8

const ios_base::fmtflags myopt = ios_base::left|ios_base::oct;

ios_base::fmtflags old_options = cout.flags(myopt); //set base to 8
// and alignment to left.

cout.precision(8); // set precision to 8
cout.setf(ios_base::scientific, ios_base::floatfield);

cout.width(4);  // output at least four characters
cout.fill('*'); // fill gaps with '*'
cin.noskipws(); // don't skip white space

Stream Iterators

Iterators can be used on streams, providing an elegant way to integrate I/O with container classes. You've seen them already in the Standard Library section.

ostream_iterator<string> oo (cout);
int main()
*oo = "Hello";
++oo;
*oo = "World";

Output of User-Defined types

One way to do this is by overloading the stream insertion operator. The following defines how complex numbers should be printed out -

ostream& operator<<(ostream&s, complex z) // returns ostream& so can be chained
{
  return s << '(' << z.real() << ',' << z.imag() << ')';
}

Input of User-Defined types

The following code reads in a complex number that's provided in the form (a,b) or (a)

istream& operator>>(istream&s, complex &a) // returns istream& so can be chained
{
 double re=0, im=0;
 char c=0;

 s>>c;
 if (c== '(') {
     s>>re >> c;
     if (c == ',') s >> im >> c;
     if (c != ')') s.clear(ios_base::badbit);

 }
 else {
   s.putback(c);
   s>> re;
 }

 if (s) a = complex(re,im);
 return s;
}

String streams

stringstreams are streams that are attached to a string rather than a file and letting you use the same syntax as file I/O. They are defined in <sstream>.

[fontsize=\small,frame=single,formatcom=\color{progcolor}]
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int main()
{
int i = 7;
string s1 = "He is ";
string s2 = " years old";

ostringstream ostring;
ostring << s1 << i << s2;

cout << "ostring =" << ostring.str() << endl;

return 0;
}