Thread: Loading file into structure

  1. #1
    Registered User
    Join Date
    Aug 2003
    Posts
    22

    Question Loading file into structure

    Hi, I'm trying to load a file into a structure. Well actually, a structure and a 3d array of structures. Very confusing for somebody like me. Here's what everything looks like.

    Code:
    struct MAPFILEHEADER
    {
        double engversion;
        char *tileset;
        char *name;
        char *leftexit;
        char *rightexit;
        char *downexit;
        char *upexit;
        int width;
        int height;
    }
    
    struct MAPTILE {
        int id;
        int width;
        int height;
    };
    
    class mapObj
    {
    	public:
    	    
              // bunch of methods
              // ......
    	
       private:
    
    	    MAPFILEHEADER mapheader;
    	    MAPTILE **tile[2];
    
            // lots of other private members.
            // ........
         
    };
    The array of MAPTILES is all allocated dynamically with one of the member functions. I have a load function already set-up but when I made the MAPFILEHEADER struct to use for saving maps I figured I could just save all my structures in one big blob, instead of looping through each element. Because I have a muliti-dimensional array of structs and because it's all allocated dynamically this has gotten me very confused. Could somebody please explain how I would go about writing this to a file? Some pseudo-code would be nice. Thanks in advance.

  2. #2
    Registered User manofsteel972's Avatar
    Join Date
    Mar 2004
    Posts
    317
    open file in binary mode
    pass address of struct and sizeof struct to fwrite and write to file.
    "Knowledge is proud that she knows so much; Wisdom is humble that she knows no more."
    -- Cowper

    Operating Systems=Slackware Linux 9.1,Windows 98/Xp
    Compilers=gcc 3.2.3, Visual C++ 6.0, DevC++(Mingw)

    You may teach a person from now until doom's day, but that person will only know what he learns himself.

    Now I know what doesn't work.

    A problem is understood by solving it, not by pondering it.

    For a bit of humor check out xkcd web comic http://xkcd.com/235/

  3. #3
    Registered User
    Join Date
    Aug 2003
    Posts
    22
    Oh... so it's that simple? Thanks I'll give it a try.

  4. #4
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    For collections that posses no dynamically allocated data or STL collections that would work fine, but once you do have those elements, writing and reading the data back becomes more... complicated. You have pointers to things and simply writing that data is only going to write an address to the file that happens to represent where your value was stored in this run of the program. When you read it back you will only end up reading an address back into that variable that will point to god only knows what. If you try to dereference that pointer value then WATCH OUT!
    "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

  5. #5
    Registered User manofsteel972's Avatar
    Join Date
    Mar 2004
    Posts
    317

    Sample code

    PLEASE BE AWARE THERE IS NO VALIDATION CODE TESTING FOR MEMORY ALLOCATION FAILURE OR FILE OPENING FAILURE!!

    Just a simple example i whipped up.

    Code:
    #include<iostream>
    #include<cstdlib>
    #include<ctime>
    
    using namespace std;
    
    struct character{
    	char name[80];
    	int	age;
    	float height;
    	int strength;
    	int intelligence;
    	int dexterity;
    	int charisma;
    	int health;
    	int armor;
    	}*lpstruct;			//structure to hold character data for rpg
    
    int main()
    {
    
    	srand((unsigned)time(NULL));	//seed randomizer
    
    
    
    
    
    FILE*fpointer=fopen("character.dat","w+b");	//open file in binary mode if not exist create file
    	lpstruct=new character;				//dynamically allocate memory for structure
    	lpstruct->age=rand()%10;			//assign random attributes
    	lpstruct->armor=rand()%15;
    	lpstruct->charisma=rand()%10;
    	lpstruct->dexterity=rand()%20;
    	lpstruct->health=rand()%100;
    	lpstruct->height=rand()%101;
    	lpstruct->intelligence=rand()%40;
    	strcpy(lpstruct->name,"george");
    	lpstruct->strength=rand()%20;
    	
    	fwrite(lpstruct,sizeof(character),1,fpointer);	//write data to file
    
    	fclose(fpointer);				//close file	
    
    	delete lpstruct;				//delete allocated memory
    
    
    	character*rlpstruct= new character;	//dynamically allocates memory for structure to read in data
    
    	fpointer=fopen("character.dat","rb");	//opens file read only in binary mode
    	fread(rlpstruct,sizeof(character),1,fpointer);	//reads data and fills structure	
    	fclose(fpointer);	//close file	
    
    	cout<<rlpstruct->height;	//output data read from file	
    	delete rlpstruct;			//delete allocated memory
    
    	return 0;
    }
    Last edited by manofsteel972; 08-14-2004 at 05:49 AM.
    "Knowledge is proud that she knows so much; Wisdom is humble that she knows no more."
    -- Cowper

    Operating Systems=Slackware Linux 9.1,Windows 98/Xp
    Compilers=gcc 3.2.3, Visual C++ 6.0, DevC++(Mingw)

    You may teach a person from now until doom's day, but that person will only know what he learns himself.

    Now I know what doesn't work.

    A problem is understood by solving it, not by pondering it.

    For a bit of humor check out xkcd web comic http://xkcd.com/235/

  6. #6
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Manofsteel:

    a) This is C++, not C. Therefore, use the standard ifstream file i/o methods.
    b) There is a fundamental difference between your structure and the one posted by spitball. Yours contains no dynamically allocated data, while spitball's does. The problems this causes is that while your structure contains a block of 80 characters in its array, meaning write() and read() will read and write the contents of the array, spitball's contains a 4-byte pointer which is 100% useless the next time the program runs. Besides which, assuming the file is entered in notepad or something similar, the string will NOT be exactly 80 characters, meaning your read() will probably read beyond the header and fill in the structure with false values.

    Spitball:

    You probably want to change your char*'s in the header structure into char arrays, for the reasons mentioned above; although, of course, that still probably won't work properly (I mean using one read() call to fill in the whole structure) - also for the reasons mentioned above. Then, assuming the file is separated by newlines (each section - tileset, name, etc. is on a different line), you can use this:
    Code:
    #include <fstream>
     
    struct MAPFILEHEADER
    {
       double engversion;
       char tileset[200];
       char name[200];
       char leftexit[200];
       char rightexit[200];
       char downexit[200];
       char upexit[200];
       int width;
       int height;
    }; //Notice the semicolon here. You need one after every structure/class declaration
     
     
    std::ifstream file("something.txt");
    file >> header.engversion;
    file.ignore(1); //Extract the trailing newline character still in the file
    file.getline(header.tileset, 200);
    file.getline(header.name, 200);
    file.getline(header.leftexit, 200);
    //etc.
    file >> header.width;
    file >> header.height;
    Ok, so that loads the MAPFILEHEADER structure. But you'll notice that the arrays are 200 in length. That means we're assuming that the input will never be more than 200 characters long, and if it's longer then we're screwed. A better way is to use std::strings and std::getline:
    Code:
    #include <fstream>
    #include <string>
     
    struct MAPFILEHEADER
    {
       double engversion;
       std::string tileset;
       std::string name;
       std::string leftexit;
     
       //...
      
       int width;
       int height;
    };
     
    std::ifstream file("something.txt");
    file >> header.engversion;
    file.ignore(1);
    std::getline(file, header.tileset);
    std::getline(file, header.name);
    std::getline(file, header.leftexit);
    //etc.
    file >> header.width;
    file >> header.height;
    This way, no matter how long each member is, it will all get loaded. You can also then check the string and compare it with the == operator (unlike having to use strcmp()), and if you need to you can convert it to a char* using "theString.c_str()".

    On the other hand, since I'm not sure how the file looks, I can't say how you'd go about loading the 2D array of tiles. Maybe if you could post a sample of the file?

    Hope this helps!
    Last edited by Hunter2; 08-14-2004 at 09:46 AM. Reason: Ooops, had several arrays of 200 strings each... lol | Oops, forgot 'header.' lol
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. File transfer- the file sometimes not full transferred
    By shu_fei86 in forum C# Programming
    Replies: 13
    Last Post: 03-13-2009, 12:44 PM
  2. Formatting a text file...
    By dagorsul in forum C Programming
    Replies: 12
    Last Post: 05-02-2008, 03:53 AM
  3. archive format
    By Nor in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 08-05-2003, 07:01 PM
  4. need help with .md3 file loading
    By Shadow12345 in forum Game Programming
    Replies: 2
    Last Post: 12-06-2002, 04:06 PM
  5. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 10:12 PM