Professional Web Applications Themes

problem with fwrite/fread and writing a struct - UNIX Programming

Hello i seen to be having the following problem: i'm using a struct like this: typedef struct mp3_index { char *mp3; char *id3; int size; struct mp3_index *next; } index; to which i have index *tail and index *head, both set to NULL. this is the code i use to add something to it but it crashes upon doing so. if i leave out the strdup, there is no problem, but then nothing gets written ofcourse. if(tail==NULL) { /* Assume that nothing was read from index file, so _ this is the first write, and the first buildup of the ...

  1. #1

    Default problem with fwrite/fread and writing a struct

    Hello

    i seen to be having the following problem:

    i'm using a struct like this:

    typedef struct mp3_index {
    char *mp3;
    char *id3;
    int size;
    struct mp3_index *next;
    } index;

    to which i have
    index *tail and index *head, both set to NULL.

    this is the code i use to add something to it
    but it crashes upon doing so.
    if i leave out the strdup, there is no problem, but then nothing
    gets written ofcourse.

    if(tail==NULL) {
    /* Assume that nothing was read from index file, so
    _ this is the first write,
    and the first buildup of the linked list */
    printf("write_index: Building new index list in
    memory\n");
    tail->mp3=strdup(mp3);
    /* Leave the rest for later */
    tail->next=NULL;
    head=tail;
    } else {
    tail->next=malloc(sizeof(index)-4);
    tail=tail->next;
    tail->mp3=strdup(mp3);
    tail->next=NULL;}

    the -4 is because i don't want the *next pointer to get read with it,
    i just want the strings, not the pointers.

    now this is what i use for writing. I'm not sure if this
    is correct to, although on first sight it would appear so:

    case WRI: if((fp=fopen(INDEX,"w"))==NULL) {
    fprintf(stderr,"write_index: can't do writeout to %
    \n",INDEX);
    exit(1);} else {
    while(tmp!=NULL) {
    fwrite(&tmp,sizeof(index)-4,1,fp);
    tmp=tmp->next;}
    fclose(fp);
    }

    where tmp is pointing to the first node

    and i use this for reading:

    while(!feof(fp)) {
    if(tail==NULL) {
    tail=malloc(sizeof(index)-4);
    head=tail;}

    fread(&tail,sizeof(index)-4,1,fp);
    tail->next=malloc(sizeof(index)-4);
    tail=tail->next;
    tail->next=NULL;
    }

    fclose(fp);
    printf("read_index: %s initialized\n",INDEX);


    I'm sorry for all the code, and the bad indentation ;-)
    any help would be most welcome

    Kind regards,
    alef
    atv Guest

  2. #2

    Default Re: problem with fwrite/fread and writing a struct

     

    Well, basically, i'm using a dirwalk like routine to scan the filesystem.
    On startup the program should read from a file, where a write has been done
    of all the nodes in my linked list. If the file is not there, it's created.

    Then, using the dirwalk routine, each file gets scanned and the properties
    put in the linked list, if it's not already there. If it's already there, it
    get's discarded.

    At the end of the program, the whole linked list collected in memory get's
    written out to the file the program first reads on startup.

    so i guess i basically need a example of the best way of doing this.

    atv Guest

  3. #3

    Default Re: problem with fwrite/fread and writing a struct

    atv <nl> wrote: 
     
     
     
     
     
     

    That doesn't make sense - you need memory for a complete structure because
    you write to the 'next' element of that structure. But this way you most
    likely write the NULL to some memory past the end of the structure, i.e.
    the memory youu own. If you're lucky the program will crash at that point.
    BTW, you can't be sure that the 'next' element is just in the last 4 bytes
    of the structure anyway, there could be additional padding bytes. And
    another thing you should keep in mind is that malloc() as well as strdup()
    can fail, so you always should check their return values...
     
     

    That also doesn't make sense: you're writing the pointers to your strings
    to the file, not the strings themselves. But the pointers are completely
    useless when you read them back - they point to the addresses the strings
    had when you wrote the file, but it's extremely unlikely that there's any-
    thing useful at that addresses when you read in the file again. Another
    problem could result when you try to read in the file on a machine with
    a different architecture than the one it was written on (or, theoretically,
    even using a different compiler could get you into trouble) because the
    representation of int's and pointers could be completely different (and
    also the number of padding bytes). That's why it's usually considered a
    rather bad idea to write structures directly into a file - better convert
    everything to ASCII and then write it out element by element.
     
     
     
     
     
     

    It probably would be easier if you would tell what exactly you want to
    do because just from your code it's rather hard to guess.

    Regards, Jens
    --
    \ Jens Thoms Toerring ___ fu-berlin.de
    \__________________________ http://www.physik.fu-berlin.de/~toerring
    Jens.Toerring@physik.fu-berlin.de Guest

  4. #4

    Default Re: problem with fwrite/fread and writing a struct



    atv wrote: 

    Your problem is that when you write data to disk, pointers
    are meaningless, especially if the program reading the data
    is not the same as the program writing the data. So, I would
    re-do your struct like this:

    typedef struct mp3_index {
    char mp3[MAX_MP3_SIZE];
    char id3[MAX_ID3_SIZE];
    int size;
    struct mp3_index *next;
    } index;

    With this struct, the string data will be included within the
    struct. Of course, you were correct to write the sizeof(index) - 4
    as the trailing pointer is also meaningless.

    An alternate method to keep your original struct, would be to write the
    string data after the struct, and rejoin the data with dynamic
    allocation on read, but this would be very tricky to implement.

    --

    Fletcher Glenn

    Fletcher Guest

  5. #5

    Default Re: problem with fwrite/fread and writing a struct

    In article <4029098f$0$558$xs4all.nl>,
    atv <nl> wrote:
     

    Even though you don't want to read the *next pointer, you still need to
    allocate space for it, because you assign to tail->next. You should do
    the subtraction when reading/writing, but not when allocating.

    Also, don't hard-code sizes; use sizeof(struct mp3_index) rather than
    the magic number 4.
     

    You're writing the structure containing pointers, but you're never
    writing the strings that the mp3 and id3 pointers point to.
     

    Now you're reading back the mp3 and id3 pointers. But they contain
    addresses that were valid in the original process that wrote the
    structures, and have no relevance in the current process. You need to
    get the contents of those strings from somewhere, and then assign the
    pointers to point to them.

    --
    Barry Margolin, mit.edu
    Arlington, MA
    *** PLEASE post questions in newsgroups, not directly to me ***
    Barry Guest

  6. #6

    Default Re: problem with fwrite/fread and writing a struct

    In article <com>,
    Fletcher Glenn <com> wrote:
     

    Another alternate method is to use a library like XDR to serialize your
    data structures.

    --
    Barry Margolin, mit.edu
    Arlington, MA
    *** PLEASE post questions in newsgroups, not directly to me ***
    Barry Guest

  7. #7

    Default Re: problem with fwrite/fread and writing a struct

    Fletcher Glenn <com> writes:
     

    What if pointers are not 4 bytes, or if there's padding in the struct?
    The correct size to write is offsetof(index, next).
     

    I go as far as calling it very tricky. Somewhat more work, but
    definitely nothing to get frightened by.

    --
    Måns Rullgård
    se
    Måns Guest

  8. #8

    Default Re: problem with fwrite/fread and writing a struct

    atv <nl> wrote:
     
     
     

    Obviously you more or less know how to deal with linked lists (just
    remember to allocate memory for the whole structure and don't make
    assumptions at what offset in the structure a certain element is;-),
    so I will concentrate on how to write the intersting part of your
    structure

    typedef struct mp3_index {
    char *mp3;
    char *id3;
    int size;
    struct mp3_index *next;
    } index;

    to a file and how to get it back from a file. You should write everything
    in ASCII to the file so you don't have to worry about reading the data
    back in with some other machine. (You may argue that you don't need to
    be concerned about that, I was thinking the same once and later learned
    the hard way what a mess I got in with this when the program started to
    get used also on a different architecture, so I now tend to be more
    careful...)

    For each string you could write the length of the string first, then some
    delimiter character (I am going to use the '|' in the example code, it
    just should be a non-digit so fscanf() won't mistake it for part of an
    integer) and then the string. Then you can write the 'size' element, also
    followed by another delimiter character (if you have some additional
    knowledge what are possible strings you could perhaps use a little less
    space but probably not much).

    Lets assume you have a structure called of type 'index' called 'idx'
    that you want to write to the file. You could do e.g.

    FILE *fp;
    size_t len;
    index idx;

    ....

    if ( idx.mp3 != NULL ) {
    len = strlen( idx.mp3 );
    fprintf( fp, "%ul|", ( unsigned long ) len + 1 );
    if ( len > 0 )
    fwrite( idx.mp3, len, 1, fp );
    } else
    fprintf( fp, "0|" );

    /* Repeat the above for idx.id3 */

    fprintf( fp, "%d\n", idx.size );

    When you use that in a loop over your linked list all the relevant
    information from each structure gets written to the file.

    To read it back into a structure you could use something like

    FILE *fp;
    unsigned long len;
    index idx;

    ....

    fscanf( fp, "%ul|", &len );
    if ( len != 0 ) {
    idx.mp3 = malloc( len );
    if ( len > 1 )
    fread( idx.mp3, len - 1, 1, fp );
    idx.mp3[ len - 1 ] = '\0';
    } else
    idx.mp3 = NULL;

    /* Repeat the above for idx.id3 */

    fscanf( fp, "%d|", &idx.size );

    And that's it. Of course, you should include lots of error checking
    (test if malloc() did succeed, test if fprintf() and fwrite wrote and
    fscanf() and fread() returned as many data items as you expected etc.
    if things don't match up the file probably got corrupted).

    If you're wondering why I am writing not the length of the string itself
    but the length including the final '\0' into the string: that makes it
    possible to distinguish between string pointers that originally were
    NULL and empty strings, i.e. strings just containing the '\0' character.

    Regards, Jens
    --
    \ Jens Thoms Toerring ___ fu-berlin.de
    \__________________________ http://www.physik.fu-berlin.de/~toerring
    Jens.Toerring@physik.fu-berlin.de Guest

Similar Threads

  1. [PHP] fwrite, fopen, or fread limit?
    By Mike in forum PHP Development
    Replies: 2
    Last Post: November 6th, 12:24 AM
  2. Issues with declaring struct arrays inside of a struct
    By Richard Mathis in forum ASP.NET Building Controls
    Replies: 0
    Last Post: October 10th, 03:14 PM
  3. fwrite text problem
    By JDJones in forum PHP Development
    Replies: 3
    Last Post: September 26th, 12:52 PM
  4. fwrite problem
    By s a n j a y in forum PHP Development
    Replies: 3
    Last Post: July 17th, 06:16 AM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139