C++ Binary Files Problem

This is a discussion on C++ Binary Files Problem within the C++ Programming forums, part of the General Programming Boards category; Hi, I'm trying to create a program that has a class called student which holds a name, age and gpa. ...

  1. #1
    Registered User
    Join Date
    Dec 2004
    Posts
    8

    C++ Binary Files Problem

    Hi, I'm trying to create a program that has a class called student which holds a name, age and gpa. Then in my main I want to create an array of student pointers. Then I want the user to be able to create students and store them into the array. Then when they exit the program it will save the array to a binary file. Then when the program is started again the binary file is read back into an array. I have everything working except the read and or write part of the binary file. When I try printing the array after I have read the file back into the array I either get results like name=nothing age=-432432 and gpa=432432 or the program spits out a bunch of garbage then crashes. Here are both functions...

    Code:
    void read(student *arr[], int& x)//reads an array from a binary file
    {
       int y=0;
       ifstream in("Binary.bin", ios::binary|ios::in);
       in.seekg (0);
    
       if(!in)
         {
            cout<<"\t\t\t"<<"No file present"<<endl;
         }
       else
         {
            arr[0]=new student;
            in.read((char*)(arr[x]),sizeof(student));
            cout<<x<<endl;
            x++;
    
            while(!in.eof())
              {
                 arr[x]=new student;
                 in.read((char*)(arr[x]),sizeof(student));
                 x++;
              }
    
            x--;
            in.close();
         }
    }
    Code:
    void write(student *arr[], int x)//writes an array to a binary file
    {
       int y=0;
    
       ofstream out("Binary.bin", ios::binary|ios::out);
    
       for(y=0;y<x;y++)
        {
           if(out.write((char*)(arr[y]),sizeof(student)))
        }
    
        out.close();
    }
    If you need anymore of the code just ask. Thank you all for any help you can provide.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,823
    > void read(student *arr[], int& x)
    Show the declaration of variable you pass to this function when you call it.

  3. #3
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    student *arr[],

    means array is an array of pointers to type student. The amount of memory necessary to hold a pointer may or may not be the same as the amount of memory necessary to hold information for an object of type student, yet that is what you are asking for with sizeof(student).

    Writing pointers to file won't work well, either, as you will be writing an address to file, not what exists at that address, to file. Who know what will be at that memory address at a later time when you read back the address from file.

    I'd suggest trying with student array[] as the first parameter, instead of student * array[], if at all possible.

  4. #4
    Registered User
    Join Date
    Dec 2004
    Posts
    8
    Thank you for your replies. I need to use an array of student pointers as opposed to an array of students. I've tried doing

    out.write((char*)(arr[y]),sizeof(student));
    vs.
    out.write((char*)(&arr[y]),sizeof(student));

    The difference was the first one would crash the program when I would try to print the array after reruning the program and the second one wouldn't crash the program but would print huge numbers in place of the variables. ex. Name should be Jane age should be 20 and gpa should be 3.4, however would print out name is nothing, age is 3234324324, and gpa is 54333656. Thank you for your time.

    Edit: This is the declaration... student * arr[10];
    However, these use to not be in functions, just part of main and I still had this problem so it's not to do with how I pass it to the function.
    Last edited by terran9; 12-13-2004 at 02:21 PM.

  5. #5
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,806
    Is the 'name' member of your student struct a pointer itself, i.e. a pointer to char representing a character array where the name is stored for you student? Or, is it just a simple character array?

    If it is a pointer then you might get weird numbers if you write/read a pointer to the file since you would be writting/reading an address and not the data you think. You would need to handle this a certain way, for example your output routine would need to write a length and then output a number of bytes equal to this length representing the name. After this you would then write the age and gpa data. Your input routine would need to read this length back in first, then allocate memory to your 'name' pointer of this length, and then read in bytes from the file equal to this length into the 'name' field followed by reading in the age and gpa bytes.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,823
    > Edit: This is the declaration... student * arr[10];
    Then
    Code:
    int foo;
    student * arr[10];
    read( student, foo );
    should be OK, so long as you don't read in more than 10 students.

    > while(!in.eof())
    Read the FAQ
    This is notorious for going round the loop one too many times, which if you're reading in just 10 students means you critically make the mistake of allocating the element just past the end of the array.

    The hacky x--; suggests that this is actually happening, as your fix to the off-by-one error which would otherwise be present.

  7. #7
    Magically delicious LuckY's Avatar
    Join Date
    Oct 2001
    Posts
    856
    Quote Originally Posted by Salem
    Code:
    int foo;
    student * arr[10];
    read( student, foo );
    should be OK, so long as you don't read in more than 10 students.
    Keep in mind that that won't work unless you stick a
    Code:
    foo = 0;
    in before the read() call since you don't initialize x anywhere in the function.
    Also note that your first block of read code is unnecessary.

  8. #8
    Registered User
    Join Date
    Dec 2004
    Posts
    8
    Thank you all for the help. I think it would be easier if I just posted a zip file containing all the files so you can see how everything is declared etc.
    Attached Files Attached Files

  9. #9
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    It's easier if you condense the problem down to something like this:
    Code:
    #include <iostream>
    #include <stdlib.h>
    #include <cstring>
    #include <fstream>
    
    using namespace std;
    
    struct Student1
    {
      char name[20];
      int age;   
    };
    	 
    int main(int argc, char *argv[])
    {
      Student1 s;
      Student1 s1;
    	
      strcpy(s.name, "tom");
      s.age = 19;
      
      Student1 * s1array[1];
      s1array[0] = &s;
     
      ofstream fout("binaryFileWriting.txt");
      fout.write((char *) s1array[0], sizeof(Student1));
      fout.close();
      
      ifstream fin("binaryFileWriting.txt");
      fin.read((char *) s1, sizeof(Student1));	
      fin.close();
      
      cout << s1.name << ' ' << s1.age << endl; 
      
      system("PAUSE"); 
      return 0;
    }
    The above creates a Student1 object, and assigns it's address to an element of s1array which is an array of Student1 pointers. The array element is then written to file in binary fashion, and read from file to a different object of the Student1 class which is then displayed on the screen to confirm that the copying, writing, reading, etc. all works out. The program.....

    (whatever the problem is can be explained here---this program seems to compile and work appropriately for me)

    Providing this type of information from your program, without all the extraneous material, would be helpful to those willing to look, and try to help.

    Thanks for posting the question. Working through it so far has helped me better understand the process better, too.

  10. #10
    Registered User
    Join Date
    Dec 2004
    Posts
    8
    Thank you for the reply. I tried compiling your code you posted but I got an error.

    fin.read((char *) s1, sizeof(Student1));

    I had to change it to

    fin.read((char *) &s1, sizeof(Student1));

    Then it worked. I tried doing this with my program(creating another object of student and reading the binary file into that) but my program crashed when I tried printing the object out.

    The only difference I see is that I use string name and you use char name[20]. Do you think this could be causing the problem? Thank you again for all your help.

  11. #11
    Registered User jlou's Avatar
    Join Date
    Jul 2003
    Posts
    1,088
    Forgive me for not re-reading the thread of downloading the zip file, but you cannot write a structure to a binary file using read and write like that if the struct contains members with complex structures. In this case, the string class most likely holds a pointer to the string data held elsewhere in memory. That data will not be written to the binary file, only the pointer to it will be written. Of course, when you read tha data back in, the pointer will be invalid, so it won't work.

    If you want to write a struct with a string member to a binary file, you will have to have a special function that specifically writes out each piece of data appropriately (and another for reading). That function should probably write the size of the string followed by the result of a call to c_str() on the string member(s), so that the read function can read in the correct number of bytes for the string the next time through.

  12. #12
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    Here's a version of my previous program using std::string for name instead of char[]. In this case using char[] instead of std::string might be worth it, although I'd probably avoid writing to binary file in first place.

    Hopefully, I didn't erase a brace or semicolon or & when I edited out comments etc before copy and pasting this version from my compiler.

    Code:
     
    #include <iostream>
    #include <string>
    #include <fstream>
    using namespace std;
     
    struct Student1
    {
     string name;
     int age; 
    };
     
    void write(ofstream & fout, Student1 * pS)
    { 
     int len = pS->name.length();
     ++len; //account for terminating null char
     fout.write((char *) &len, sizeof(int));
     fout.write(pS->name.c_str(), len); 
     fout.write((char *) &(pS->age), sizeof(int));
    }
     
    void read(ifstream & fin, Student1 * pS)
    { 
     int len;
     fin.read((char *) &len, sizeof(int));
     
     char * str = new char[len];
     fin.read(str, len);
     pS->name = str;
     delete str;
     
     fin.read((char *) &(pS->age), sizeof(int)); 
    }
     
    int main(int argc, char *argv[])
    {
     Student1 s;
     Student1 s1;
     
     s.name = "tom";
     s.age = 19;
     
     Student1 * s1array[1];
     s1array[0] = &s; 
     
     ofstream fout("binaryFileWriting.txt");
     write(fout, s1array[0]);
     fout.close();
     
     Student1 * s1array2[1]; 
     s1array2[0] = new Student1; 
     
     ifstream fin("binaryFileWriting.txt");
     read(fin, s1array2[0]);
     fin.close();
     
     cout << s1array2[0]->name << ' ' << s1array2[0]->age << endl;
     
     delete s1array2[0];
     
     system("PAUSE"); 
     return 0;
    }

  13. #13
    Registered User
    Join Date
    Dec 2004
    Posts
    8
    I couldn't get it to work with passing an array of pointers to students to the binary file, so I had an object equal what the pointer was pointing to then I passed the object. However, I still couldn't get it to work with a string. So I changed it to an array of chars, however, that still didn't work so I just scrapped the name. If anyone knows how you can pass an object of a class that contains a string to a binary file, I would like to know. Thank you all for your help.

  14. #14
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    This works on Dev-C++ though I couldn't get it to work on VC6 with similar syntax the other night when I was working on this. I'll retry later with VC6 to see if I screwed up somehow earlier (not an impossibility), or if there's a difference between VC6 and DevC++.
    Code:
    #include <iostream>
    #include <string>
    #include <fstream>
    using namespace std;
     
    struct Student1
    {
     string name;
     int age; 
    };
     
    void write(ofstream & fout, Student1 * s1array[], int size )
    {
     int len;
     int i;
     for(i = 0; i < size; ++i)
     {
       len = (s1array[i]->name).length();
       fout.write((char *) &len, sizeof(int));
       fout.write((char *) &(s1array[i]->name), len);
       fout.write((char *) &(s1array[i]->age), sizeof(int));
     }   
    }
     
    void read(ifstream & fin, Student1 * s1array2[], int size)
    {
      int i;
      int len;
      for(i = 0; i < size; ++i)
      {
    	fin.read((char *) &len, sizeof(int));
    	fin.read((char *) &(s1array2[i]->name), len);
    	fin.read((char *) &(s1array2[i]->age), sizeof(int));
      }	 
    }
     
    int main(int argc, char *argv[])
    {
     Student1 s;
     Student1 s1;
     
     s.name = "tom";
     s.age = 19;
     
     Student1 * s1array[1];
     s1array[0] = &s; 
     
     int size = 1;
     
     ofstream fout("binaryFileWriting.txt");
     write(fout, s1array, size);
     fout.close();
     
     Student1 * s1array2[1]; 
     s1array2[0] = new Student1; 
     
     ifstream fin("binaryFileWriting.txt");
     read(fin, s1array2, size);
     fin.close();
     
     cout << s1array2[0]->name << ' ' << s1array2[0]->age << endl;
     
     delete s1array2[0];
     
     system("PAUSE"); 
     return 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 12
    Last Post: 02-12-2009, 02:39 PM
  2. Problem with Binary Files I/O (fread function)
    By g33koo in forum C Programming
    Replies: 21
    Last Post: 09-30-2008, 05:56 AM
  3. Problem compiling files that store functions
    By tiachopvutru in forum C++ Programming
    Replies: 10
    Last Post: 05-30-2008, 06:42 PM
  4. Help with binary files
    By tuxinator in forum C Programming
    Replies: 3
    Last Post: 12-01-2005, 02:11 AM
  5. binary tree problem - help needed
    By sanju in forum C Programming
    Replies: 4
    Last Post: 10-16-2002, 06:18 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21