2

I'm working on a mailbox project, and I have these two structures:

struct mmbox_mail

struct mmbox_mail {
  char *sender, *recipient; 
  char *obj, *date;
  char flags; 
  size_t size; 
};

and

mail_t

typedef struct{
  struct mmbox_mail info;
  void *body;
  void *next;
} mail_t;

I cannot modify the structures' fields, because I need variable data (for this purpose I used char* instead of char[]).

Each mail_t structure is a mail. I need to save every mail of a user in a file, that could be binary or text file (but I think it's better with a binary file, because I have the void* body that is difficult to save in plain text.

I tried to do this, but it seems like it doesn't work:

while(mailtmp != NULL){
  fwrite(mailtmp, sizeof(mail_t), 1, fp);

  /* next mail */
  mailtmp=mailtmp->next;
}
while(mailtmp != NULL){  /* i have a list of mails and i use a mailtmp pointer to save each mail */

Could you help me? I tried to search everywhere but I never found someone that ask to save two structures, one inside one other.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
user1111399
  • 21
  • 1
  • 2

3 Answers3

3

Of course, that will not work as for strings it will copy the size of pointer, (usually 4 bytes). I see 3 options here:

  1. Serializing data, binary file (http://en.wikipedia.org/wiki/Serialization).
  2. Creating a format to store data in a text file.
  3. Use markup language like XML/JSON etc.

In any case you would need to go through every field of the structure in order to write it to data file. As for reading, in first 2 cases you would have to do reading exactly in the order you wrote the data, in third case you would be able to read fields independently in any order.

In case you choose first method, for every string (char *) field write also zero-termination byte so that you always know where it ends when reading it back.

dimir
  • 693
  • 6
  • 23
  • Ok, i can't use XML/JSON, ecc.. because i don't know that :( I tried to create a format to store data (like saving sender then saving recipient then saving data, ecc...) but it don't seems very efficient.. (any suggestion is accepted.. :) ) By the way, i'll look for serialization.. :) – user1111399 Dec 22 '11 at 09:55
  • The idea of serializing data is that you write the parts in exactly the same order as you read it. So, e. g. if you need to store customers with name, age, address, you would open file and while not EOF: write name (with zero-termination byte), write age (integer, 4 bytes), write address (with zero-termination byte). The reading would be: open file, while not EOF: read chars until zero-char into buffer (name), read 4 bytes (age), read chars until zero-char into buffer (address). – dimir Dec 22 '11 at 10:08
  • Ok. I got it. Today i write that routine again and i keep you in touch. :D (really sorry for my bad english.. :( ) Thanks so much! :D – user1111399 Dec 22 '11 at 13:33
  • Past discussion of serialization possibilities here: http://stackoverflow.com/questions/371371/serialize-data-structures-in-c – dimir Dec 22 '11 at 13:51
  • Also, if you are familiar with SQL would you consider to use libsqlite? Especially if there is lots of data. – dimir Dec 22 '11 at 13:57
  • well, i'm not so good with sql, so i prefer to learn something new about files, and then focus my attention about the manner to make it better. :) Anyway, i created this two sources that seems work: you can find the "writer" here (http://pastebin.com/bRiCXfvw) and the "reader" here (http://pastebin.com/mUsxp69b) .. could you tell me if in your opinion this method will work on my project? I think of yes, but maybe i forgot something.. :) Thanks another time! :D – user1111399 Dec 22 '11 at 14:06
  • the only problem i have with this two sources, is in the char* saving. I cannot know the lenght of each text, so i limited it at BUFSIZ (stdlib.h). It works, but it is a waste of memory.. i don't know how i can solve.. :( – user1111399 Dec 22 '11 at 14:08
  • I solved in the way below. "writer": http://pastebin.com/gBncFtw9 - "reader": http://pastebin.com/SKcPM8Bh .. Thanks a lot for the help. I solved saving in the file also the length of the string. I know, i waste sizeof(int) bytes of space for each string i need to save, but it is the better i can do.. anyway, any suggestions are accepted! :D Really thanks! :D – user1111399 Dec 22 '11 at 19:16
0

What you're doing is saving the literal binary representation of mail_t into the text file, which is just a bunch of pointers. What you want to do is something to the effect of:

fprintf( fp, "To: %s\nFrom: %s\n....\nContents: %*s\n\n", mailtmp->info.recipient, mailtmp->info.sender, mailtmp->info.size, mailtmp->body );

That will render the values pointed to as a string and save it to the file. A pointer to a location in memory held by your application is a bit useless to most people after said application closes ;)

EDIT: "Could you help me? I tried to search everywhere but i never found someone that ask to save two structures, one inside one other."

If you just had first class data types, such as ints or floats etc, your method would work perfectly. However, since you are using second class types, namely your char and void arrays, you have to actually specify how the data pointed to should be saved.

Kaslai
  • 2,445
  • 17
  • 17
  • I tried this way, but a problem that i found is: how to save in plain text the void *body? I mean, the body of the email could be every kind of data, so i cannot save it as plain text .. or no? O.o – user1111399 Dec 22 '11 at 09:47
  • Well the E-Mail format is inherently plaintext. Binary files attached to an E-Mail are base64'd to permit transfer over the plaintext protocol. You could write a parser to extract the actual text from the E-Mail; you could parse out the files, de-base64 them, and fwrite() them to files; you can do anything you want. The scope of your question does not cover this however, and it is completely up to you to decide how you will go about this. – Kaslai Dec 22 '11 at 10:16
  • I'm sorry but mine is a "homemade" projects that i want to run locally, and not remotely.. so i'm looking for something a little less complicated :) In the future i will implement functions to make it run remotely, but at the moment i want to let it work locally.. :) Anyway, thanks! :D – user1111399 Dec 22 '11 at 14:17
  • if you want, you can join to the discussion with dimir's answer.. :) If you have any ideas, i'm here ready to read! :) – user1111399 Dec 22 '11 at 14:18
0

well,you are storing the struct's pointer into file.not the data it point to.even you store the struct you want.it is hard to get it from file. i think you need a serialization component like google protocal buffer. then you can write a adaptor,translate the struct to probuf object,then store it to file.when you want,retr it.hoping it will help you:)

yancl
  • 263
  • 1
  • 7
  • Really appreciate your help! :D But, i think i've solved with dimir's answer.. i said "i think" 'cause i'm not sure.. – user1111399 Dec 22 '11 at 13:44