Re: [ROOT] iostream

From: Christian Holm Christensen (cholm@hehi03.nbi.dk)
Date: Mon Sep 29 2003 - 16:22:01 MEST


Dong Zhou <nosarthur@yahoo.com.cn> wrote concerning
  [ROOT] iostream [Mon, 29 Sep 2003 20:04:17 +0800 (CST)] 
----------------------------------------------------------------------
> dear rooters:
>  
> i feel there is something wrong with the 'fin >>' method.


Nothing wrong.  
  
> it should be 0 0.1 0.2
> but the output turns out to be 0.1 0.2 0.2
> it seems that it take 00.1 as 0.1

Look in `tmp.dat' - what you see is 

  > cat tmp.dat 
  00.10.2  

So the first `std::ostream& operator>>(ostream&,double&)' will read
`00.10' - that is, as much as possible consistent with a number.  The
next read will read `.2', and the third will actually fail.  

Try inserting the line 

  for(int i=0;i<3;++i){
    fin >> arr;
    if (fin.fail()) cout << "bad read: " << flush; // Added 
    cout << i << ' ' << arr << endl;
  }

and you'll see it. 

> i am not sure if i have made any mistake. what is ur opinion?

You did. What you need to do, is to put some white space (which is
ignored per default by all `template <typename T> std::ostream
operator>>(std::ostream&, T&)'), after you output the number in the
first loop.  Also, it's always a good idea to check if your read was
successful, and if not fail.  See the (pure C++) code below: 

  #ifndef __IOSTREAM__
  #include <iostream>
  #endif
  #ifndef __FSTREAM__
  #include <fstream>
  #endif
  #ifndef __VECTOR__
  #include <vector>
  #endif
  #ifndef __STDEXCEPT__
  #include <stdexcept>
  #endif
  
  int main()
  {
    try {
      std::vector<double> fixed(3);
      fixed[0] = 0;
      fixed[1] = 0.1;
      fixed[2] = 0.2;
      std::ofstream out("tmp.dat");
      
      for (std::vector<double>::const_iterator i = fixed.begin(); 
  	 i != fixed.end(); ++i) 
        out << (*i) << "\t";
      out << std::endl;
      out.close();
      
      std::ifstream in("tmp.dat");
      std::vector<double> read;
      
      while (!in.eof()) {
        double tmp;
        in >> tmp;
        if (in.eof()) break;
        if (in.fail()) throw std::runtime_error("failed during read");
        read.push_back(tmp);
      }
  
      if (fixed.size() != read.size()) 
        throw std::runtime_error("short read");
      for (std::vector<double>::const_iterator i = fixed.begin(), 
  	   j = read.begin(); i != fixed.end() && j != read.end(); 
  	 ++i, ++j) {
        std::cout << "output: " << *i << "\tinput: " << *j << std::endl;
        if (*j != *i)
  	throw std::runtime_error("input and output differ");
      }
    }
    catch(std::exception& e) {
      std::cerr << e.what() << std::endl;
      return 1;
    }
    return 0;
  }
  
The thing to remember is that the `put-to' and `get-from' operators do
_formatted_ Input/Output, and not binary I/O.  To do binary I/O, you
should use the `get' and `put' member functions of `template <typename
CharT> class basic_iostream' (and similar) or the C FILE interface.
Read the GNU LibStdC++ manual on this - it explains these issues in
details.   I don't think M$DN comments on this, as must of the
documentation is ripped from the ISO/IEC C++ Standard, which is
remarkably quite on these (and other) issues, but I may be wrong.  

Yours, 

 ___  |  Christian Holm Christensen 
  |_| |	 -------------------------------------------------------------
    | |	 Address: Sankt Hansgade 23, 1. th.  Phone:  (+45) 35 35 96 91
     _|	          DK-2200 Copenhagen N       Cell:   (+45) 24 61 85 91
    _|	          Denmark                    Office: (+45) 353  25 404
 ____|	 Email:   cholm@nbi.dk               Web:    www.nbi.dk/~cholm
 | |



This archive was generated by hypermail 2b29 : Thu Jan 01 2004 - 17:50:15 MET