0

I have this code:

#include <fstream>
#include <iostream>
using namespace std;

class Student
{
public:
    char   FullName[40];
    char   CompleteAddress[120];
    char   Gender;
    double Age;
    bool   LivesInASingleParentHome;
};

int main()
{
    Student one;
    strcpy(one.FullName, "Ernestine Waller");
    strcpy(one.CompleteAddress, "824 Larson Drv, Silver Spring, MD 20910");
    one.Gender = 'F';
    one.Age = 16.50;
    one.LivesInASingleParentHome = true;

    ofstream ofs("fifthgrade.ros", ios::binary);

    ofs.write((char *)&one, sizeof(one));

    Student three;
    strcpy(three.FullName, "three Waller");
    strcpy(three.CompleteAddress, "three 824 Larson Drv, Silver Spring, MD 20910");

    three.Gender = 'M';
    three.Age = 17;
    three.LivesInASingleParentHome = true;

    //ofstream ofs("fifthgrade.ros", ios::binary);

    ofs.write((char *)&three, sizeof(three));*/
    Student two;

        ifstream ifs("fifthgrade.ros", ios::binary);
    while(!(ifs.eof())){
    ifs.read((char *)&two, sizeof(two));

    cout << "Student Information\n";
    cout << "Student Name: " << two.FullName << endl;
    cout << "Address:      " << two.CompleteAddress << endl;

    if( two.Gender == 'f' || two.Gender == 'F' )
        cout << "Gender:       Female" << endl;

    else if( two.Gender == 'm' || two.Gender == 'M' )
        cout << "Gender:       Male" << endl;
    else
        cout << "Gender:       Unknown" << endl;

    cout << "Age:          " << two.Age << endl;
    if( two.LivesInASingleParentHome == true )
        cout << "Lives in a single parent home" << endl;
    else
        cout << "Doesn't live in a single parent home" << endl;


    cout << "\n";
    }
    return 0;
}

When i read from file, the last object prints twice. What should I do?

Jack Bonneman
  • 1,773
  • 16
  • 23
  • 2
    Writing structures like this is not portable. It depends on host-specific packing, floating point representation, and all sorts of ugly stuff, and includes holes in the structure. You should write it in a serialized, normalized form. – Seth Robertson Jun 30 '11 at 22:06
  • @Seth: you are right. I think it is fair to say, this is most likely homework, and this is ok for the sample – sehe Jun 30 '11 at 22:09
  • @sehe: Train them up right before they have a chance to make mistakes like this in more serious projects. – Seth Robertson Jun 30 '11 at 22:15

3 Answers3

1

Try

while(ifs.read((char *)&two, sizeof(two)))

instead of

while(!(ifs.eof()))

Also try formatting your code :)

#include <fstream>
#include <iostream>

using namespace std;

class Student
{
    public:
        char   FullName[40];
        char   CompleteAddress[120];
        char   Gender;
        double Age;
        bool   LivesInASingleParentHome;
};

int main()
{
    /*Student one;
      strcpy(one.FullName, "Ernestine Waller");
      strcpy(one.CompleteAddress, "824 Larson Drv, Silver Spring, MD 20910");
      one.Gender = 'F';
      one.Age = 16.50;
      one.LivesInASingleParentHome = true;
      ofstream ofs("fifthgrade.ros", ios::binary);
      ofs.write((char *)&one, sizeof(one));
      Student three;
      strcpy(three.FullName, "three Waller");
      strcpy(three.CompleteAddress, "three 824 Larson Drv, Silver Spring, MD 20910");
      three.Gender = 'M';
      three.Age = 17;
      three.LivesInASingleParentHome = true;
    //ofstream ofs("fifthgrade.ros", ios::binary);
    ofs.write((char *)&three, sizeof(three));*/
    Student two;
    ifstream ifs("fifthgrade.ros", ios::binary);
    while(ifs.read((char *)&two, sizeof(two)))
    {
        cout << "Student Information\n";
        cout << "Student Name: " << two.FullName << endl;
        cout << "Address:      " << two.CompleteAddress << endl;
        if( two.Gender == 'f' || two.Gender == 'F' )
            cout << "Gender:       Female" << endl;
        else if( two.Gender == 'm' || two.Gender == 'M' )
            cout << "Gender:       Male" << endl;
        else
            cout << "Gender:       Unknown" << endl;
        cout << "Age:          " << two.Age << endl;
        if( two.LivesInASingleParentHome == true )
            cout << "Lives in a single parent home" << endl;
        else
            cout << "Doesn't live in a single parent home" << endl;
        cout << "\n";
    }

    return 0;
}
sehe
  • 328,274
  • 43
  • 416
  • 565
  • Are you quite sure that ifs turns a value which will do something useful with the while test? The docs suggest that it returns the stream and you have to check the stream for errors. It might return false on fail(), but will not return false on eof(). – Seth Robertson Jun 30 '11 at 22:12
  • @Seth: The docs also unveil that streams have an implicit conversion to `void*` which exists explicitely to test for errors (not just eof). **Edit**: see http://www.cplusplus.com/reference/iostream/ios/operator_voidpt/ – sehe Jun 30 '11 at 22:20
  • @sehe: According to your reference it checks for *errors* (failbit and badbit), and *not* eof. eofbit is different from failbit or badbit (see http://www.cplusplus.com/reference/iostream/ios_base/iostate/). On the other hand, if it is in an integer context it will return the number of bytes (which will be zero for EOF which will terminate the loop). -1 is returned on error (which is inappropriately treated as success in this example code). – Seth Robertson Jul 01 '11 at 17:41
  • See [here](http://stackoverflow.com/questions/4533063/how-does-does-ifstream-eof-work/4533102#4533102); Use `fstream::eof` e.g. when using exception-mode of iostreams lib: http://en.wikipedia.org/wiki/Fstream; Further refs: http://bytes.com/topic/c/answers/662020-ifstream-eof-not-reporting-eof, – sehe Jul 01 '11 at 17:45
  • Oh, and of course Marshal Cline's FAQ contains the entry [`15.4` How does that funky `while (std::cin >> foo)` syntax work?](http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.4) and [`15.5`](http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.5) – sehe Jul 01 '11 at 17:47
1

If I were guessing, and it is a good guess, it would be the feof test in the loop. It probably is detecting feof after it reads on the next line and fails to get a full record.

You should have the read in the while loop and test for inappropriate reply, or at least check for feof again after the read.

Seth Robertson
  • 27,856
  • 5
  • 55
  • 52
0

Well for starter you could rewrite it so the class has a serialize/deserialize method which expects an output/input stream parameter. This code is not reusable. You also want to rewrite the code for doing output std::ostream& operator<<(std::ostream& s, Student const& rhs), etc.. Your code is a big pile of censored. If you rewrite it the main logic is going to be a couple of lines and everybody who spends 30 seconds checking it can show where the problem is.

Karoly Horvath
  • 88,860
  • 11
  • 107
  • 169