Archived

This topic is now archived and is closed to further replies.

Wavewash

Binary Output Problem

Recommended Posts

Hey all, The following code has two structures. One structure(integercon) holds ann array of the other structure(integerhold) and an integer value of the number of structures in the array. The second structure(integerhold) contains an array of integers and a integer that contains the number of integers in the array. Now the program takes in two numbers from the user. Creates an array of the sizes taken accordingly and then fills the integers in the embedded array with random numbers. Then it outputs the structure in binary to a file. Then the file is accessed and the structure is retrived from the file. I expect that the program would go through the retrived structure and print out the numbers that it put in instead it repeatedly prints the last numbers inserted into the last structure. Can someone explain to me why this happens?
  

struct integerhold{
	int * darray;
	int amt;
};

struct integercon{
	int numcon;
	integerhold * conts;
};

void main()
{
	int amt, conts;
	integercon outstruct, instruct;
	cout<<"How large?:";
	cin>>amt;
	cout<<endl<<"How many?:";
	cin>>conts;

	outstruct.numcon=conts;
	outstruct.conts=new integerhold[conts];

	srand(time(NULL));

	ofstream fout("file.dat", ios::binary);

	for(int y=0; y<conts; y++){
		for(int x=0; x<amt; x++){
			outstruct.conts[y].darray[x]=rand()%100;
			cout<<outstruct.conts[y].darray[x]<<endl;
		}
	}

	cout<<"Read in Output:"<<endl;
	
	fout.write((char *)(&outstruct), sizeof(outstruct));
	fout.close();

	ifstream fin("file.dat", ios::binary);
	fin.read((char *)(&instruct), sizeof(instruct));
	
	for( y=0; y<conts; y++){
		for(int x=0; x<amt; x++){
			cout<<outstruct.conts[y].darray[x]<<endl;
		}
	}

	fin.close();

}


    
The program outputs: How large?:2 How many?:5 46 46 26 84 98 47 87 66 27 92 Read in Output: 27 92 27 92 27 92 27 92 27 92 Press any key to continue When I expect it would output: How large?:2 How many?:5 46 46 26 84 98 47 87 66 27 92 Read in Output: 46 46 26 84 98 47 87 66 27 92 Press any key to continue Any ideas would be appreciated. Thanks so much! ~Wave Btw, if you would like to compile don't forget to include: #include <fstream.h> #include <iostream.h> #include <stdlib.h> #include <time.h> [edited by - Wavewash on May 3, 2003 4:14:28 AM]

Share this post


Link to post
Share on other sites
Hmmm... well, I don''t see anywhere that you are allocating space for the integer arrays in your integer hold structs...

peace and (trance) out

Mage

Share this post


Link to post
Share on other sites
Your program has a flaw, your are outputting the binary image of the structs directly to the file, that will not work. What will be stored in the file is only 8 bytes (if you are running on a system with 32-bit ints and 32-bit pointers) as this:

+-4 bytes-+-4 bytes-+
| numcon | conts |
+---------+---------+
As you see you are not storing the integerhold array, but only the pointer. That pointer will be invalid the next time you run the program.

And as Endurion said: "Try cout-ing the instruct, not the outstruct."



Update GameDev.net system time campaign - success at last

[edited by - dalleboy on May 3, 2003 6:18:04 AM]

Share this post


Link to post
Share on other sites
That''s exactly what I thought Dalleboy. But what confuses me is that lets say the code only looked like this. I''m only using one structure allocating the memory for the one pointer in the structure acording to the size and then writting to the file. Now when I read, I don''t even have to mess with the memory allocation of the structure I''m filling. It does it automatically:

  
int amt;
integerhold outstruct, instruct;
cout<<"How large?:";
cin>>amt;

outstruct.amt=amt;
outstruct.darray=new int[amt];

srand(time(NULL));

ofstream fout("file.dat", ios::binary);

for(int x=0; x<amt; x++){
outstruct.darray[x]=rand()%100;
cout<<outstruct.darray[x]<<endl;
}

cout<<"Read in Output:"<<endl;

fout.write((char *)(&outstruct), sizeof(outstruct));
fout.close();

ifstream fin("file.dat", ios::binary);
fin.read((char *)(&instruct), sizeof(instruct));

for(x=0; x<amt; x++){
cout<<instruct.darray[x]<<endl;
}

fin.close();


Then it outputs perfectly:
How large?:10
45
96
52
16
8
40
67
41
18
15
Read in Output:
45
96
52
16
8
40
67
41
18
15
Press any key to continue

But this doesn''t work for nested structures. That''s why I''m confused. Anyone have any clues?

~Wave

Share this post


Link to post
Share on other sites
quote:
Original post by Wavewash
Now when I read, I don't even have to mess with the memory allocation of the structure I'm filling. It does it automatically.

Not exactly, what you are doing is copying a pointer in a very inefficient way, by writing it down to a file and read it back. You can accomplish the same results by just writing instruct = outstruct;

The way to solve it is to write a (member) function that writes/reads each member to/from the stream:

  
struct integercon
{
int numcon;
integerhold * conts;
integercon();
void write(std::ostream& os) const;
void read(std::istream& is);
};

integercon::integercon()
: numcon(0),
conts(0)
{
}

void integercon::write(std::ostream& os) const
{
os.write(reinterpret_cast<const char*>(&numcon), sizeof(numcon));
for (int con = 0; con < numcon; ++con)
{
conts[con].write(os);
}
}

void integercon::read(std::istream& is)
{
is.read(reinterpret_cast<char*>(&numcon), sizeof(numcon));
delete [] conts;
conts = numcon ? new integerhold[numcon] : 0;
for (int con = 0; con < numcon; ++con)
{
conts[con].read(is);
}
}

Repeat pattern for integerhold. And add errorchecking.



Update GameDev.net system time campaign - success at last

[edited by - dalleboy on May 3, 2003 7:13:30 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by dalleboy
The way to solve it is to ...

Actually there are no single BEST solution. There are many ways to solve it, what I wrote is just one of them.



Update GameDev.net system time campaign - success at last

Share this post


Link to post
Share on other sites
quote:
Original post by Wavewash
#include <fstream.h>
#include <iostream.h>

You should change your includes to the C++ standard headers:
#include <fstream>
#include <iostream>




Update GameDev.net system time campaign - success at last

Share this post


Link to post
Share on other sites
Thankyou so much dalleboy. That cleared it all up for me. I wasn''t sure if I was reading it incorrectly or if I''d have to individually go through and fill the structure. I''m in the process of changing my ascii milkshape exporter to binary and was doing this project for learning purposes and you helped me immensly along the way. Thankyou so much!
~Wave

Share this post


Link to post
Share on other sites