Sign in to follow this  
Shadowflare

Writing structs to a file

Recommended Posts

Hello, I am trying to save a struct containing character arrays (char string[16], not char *string) to a file. I have done much research and turned up nothing concerning a way to do this. All I've managed is saving structs containing numbers. If it's even possible to do it, how could I go about this? Thank you!

Share this post


Link to post
Share on other sites
Are you using the C or C++ standard library routines? And what have you tried to write structs with numbers out to a file? Functions like fwrite() or std::basic_ostream::write() do the trick for me.

Share this post


Link to post
Share on other sites
Well, if you want to just save the data in a binary format, you can use fwrite() to write out all the struct data to the file. If you want to be able to open the file up and be able to see human-readable characters, you should write the data line-by-line or however else using something like fputs().

To write the entire structure to a binary file, you can do something like this:


// Little player struct
struct player_t
{
char name[32];
int life;
};

int WriteStructToFile(player_t *ch, const char *filename)
{
FILE *fp = fopen(filename, "wb");
if(fp)
{
fwrite(ch, sizeof(player_t), 1, fp);
fclose(fp);
return 1;
}
else
return 0;
}




-noix-

Share this post


Link to post
Share on other sites
Everything is possible my man. It's just you'll have to do it manually that's all.
If you directly write that structure to a file it will write the value of string (a memory address) instead of what is stored within that address since it is a memory pointer (Yes char* & char [] are for sake of argument exactly the same thing).
If you want to store that structure you are going to have to do it manually. make some export & input function that's all, instead of just expecting to dump the contents of memory that store that structure & expect it to work. You've failed to mention weather you're using c or c++ although many connect the term struct with C & class with C++ (although both serve the same purpose in C++, just different default access).

But either way the theory is the same:
Just write the string out as you would normal text to a file & do the same for each member in the structure. Make sure you keep the same order on load. Erm, to be short.. just write it to file one thing @ a time. Can't see what trouble or confusion you could have with that. Looks like you've just jumped ahead too fast that's all. Your brain just needs to learn some more code concept. You'll cram it all in there in the end.

Seek & you shall find knowledge & understanding

///
Edit: wow 2 people posted before me, gettin slow n old :(
//

Share this post


Link to post
Share on other sites
Quote:
Original post by ProPuke
Yes char* & char [] are for sake of argument exactly the same thing


This is actually not true for strings within structures. Try this to test your hypothesis:


typedef struct {
char Cool[32];
int SomeStuff;
} Test1;

typedef struct {
char BestEver[1024];
int SomeStuff;
} Test2;

cout << "Size 1 is " << sizeof(Test1) << "Size 2 is " << sizeof(Test2) << endl;



If your hypothesis is correct, then Test1 and Test2 would be the same size. In my experience, this has never been the case ;~).

Share this post


Link to post
Share on other sites
I wrote up a quick test just to make sure I didn't forget something. It worked fine:

#include <cstdio>

struct s
{
char a[16];
char b[16];
};

int main()
{
s v;
strcpy(v.a, "0123456789ABCDE");
strcpy(v.b, "~!@#$%^&*()_+|");

FILE* pFile = fopen("Test.dat", "wb");
fwrite(&v, sizeof(v), 1, pFile);
fclose(pFile);

return 0;
}


And as Apocryphiliac said, char* and char[] are not the same in this context. The former stores only a single (typically 4-byte) pointer. It may point to memory elsewhere, but if you try to write the struct out to a file using fwrite() or ostream::write(), you're only going to write the pointer values out to memory, not what they point to. This is not the desired behavior in almost all cases. However, with char[], the character array is stored literally in the struct, there is no pointer involved at all in this context, so the bytes get written out just as you would expect.

Share this post


Link to post
Share on other sites
Bah I knew people would complain if I said that :(
I only said "for sake or argument" although I realize I probally shouldn't of said that @ all. Since it's an array it will be allocated in the structure, & will be dereferenced by default; But ergh.. I forget what my point was. Hmm.. nope it's gone sorry

Share this post


Link to post
Share on other sites
Quote:
Original post by ProPuke
... good stuff ...


To expand on this, it is a good idea to write how many bytes long the array is in the file. This way, you can reserve a buffer long enough to hold the data before you read it in. This can prevent some buffer overrun errors as long as you adhere to that length.



struct PERSON {
int age;
char *name;
}

int write_struct(FILE *file, struct PERSON *person)
{
int length;

ASSERT(file != NULL);
ASSERT(person != NULL);
ASSERT(person->name != NULL);

fwrite(&person->age, sizeof(person->age), 1, file);

/* here i'm calculating the total number of bytes
* occupied by the string. i'm not counting on
* the size of each character in the string being
* one byte.
*/

length = strlen(person->name) * sizeof(char);
/* we write the size in bytes of the string, not
* the number of characters. this will help prevent
* buffer overruns when you read the file in later
*/

fwrite(length, sizeof(length), 1, file);
fwrite(person->name, 1, length, file);

return 0;
}

int read_struct(FILE *file, struct PERSON *person)
{
int length;

ASSERT(file != NULL);
ASSERT(person != NULL);

fread(&person->age, sizeof(person->age), 1, file);

/* read the number of bytes to allocate. when we
* wrote the value originally, we calculated byte
* length, not number of characters.
*/

fread(&length, sizeof(length), 1, file);
person->name = malloc(length);
fread(person->name, 1, length, file);

return 0;
}


Share this post


Link to post
Share on other sites
Quote:
Original post by smr
Quote:
Original post by ProPuke
... good stuff ...


To expand on this...

Ahh yes i often say that... No wait.. I didn't say that. Huh? wha.. *explodes*

Share this post


Link to post
Share on other sites
Quote:
Original post by ProPuke
Quote:
Original post by smr
Quote:
Original post by ProPuke
... good stuff ...


To expand on this...

Ahh yes i often say that... No wait.. I didn't say that. Huh? wha.. *explodes*


You're making my brain hurt!

Share this post


Link to post
Share on other sites
Quote:
Original post by smr
Quote:
Original post by ProPuke
Quote:
Original post by smr
Quote:
Original post by ProPuke
... good stuff ...


To expand on this...

Ahh yes i often say that... No wait.. I didn't say that. Huh? wha.. *explodes*


You're making my brain hurt!

Don't double quote-me-quote-you-quote-me-on me!

Share this post


Link to post
Share on other sites
Quote:
Original post by smr
This can prevent some buffer overrun errors as long as you adhere to that length.


Actually, in the case of a potentially insecure source (i.e. if you are reading from the network or a file can be modified), this can _cause_ buffer overrun errors. The ASN.1 data format (used by SNMP and a number of other protocols) uses this method, and is notoriously insecure because of it. If you really want to mess up that peice of code you have, create a file and modify the length field to be -1. Or put in a really long string and say that the length is 1. Much havoc may ensue. In a simple program, it will probably just cause a crash or give you invalid data (which is a possibility no matter what format you use), but in a complicated server application it can be a severe security hole.

Of course, if you can place a sane limit on the length of a string (for example say that monster names can be no longer than 64 characters), it is very easy to work around this problem and detect invalid data.

And if you're worried about buffer overflow problems with writing a structure binary to the file, just assign the last byte in the string to be null after you fread from the file (which you should probably make sure you do anyway). Placing a structure binary in a file is not always the best solution for a production product. However, if you're lazy it can be a quick easy temporary solution

Share this post


Link to post
Share on other sites
Right. As I said, can prevent *some* errors. [smile] Placing a nul character at the end of the buffer is something I've been doing for a long time.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this