OhSnap
OhSnap

Reputation: 376

C pointer, struct and fwrite

I'm currently trying to write and read a simple linked list into a file, but it doesn't really seem to work and I'm not sure if it is even possible.

typedef struct flug
{
    int            flugnummer;
    char            flugziel[50];
    enum TAG        flugtag;
    int            flugzeit_stunde;
    int            flugzeit_minute;
    int            gateway;
    char            status[10];
    struct flug    *next;
}FLUG;

typedef FLUG *ELEM_ZGR;

I fear the problem might be that I'm not only writing chars, but int .. and especially enums, too.

int fluege_sichern() {
ELEM_ZGR curr;

FILE *fp;
char* tag;

curr = first;

if (fopen_s(&fp, datei,"a+b") != 0) {
    printf("\nDatei %s nicht zum Anhaengen zu oeffnen",datei);
    PAUSE;
    exit(1);
}

for(curr = first; curr != NULL; curr = curr->next) {
    fwrite(curr, sizeof(FLUG), 1, fp);
}

    fclose(fp);
    return 1;
}

This is supposed to be the function to write the elements into a file as binaries. I don't get any errors in this function.

void fluege_laden() {
ELEM_ZGR curr;
FILE *fp;
int i = 0;

if (fopen_s(&fp, datei,"rb") != 0) {
    printf("\nDatei %s nicht zum Lesen zu oeffnen",datei);
    PAUSE;
    exit(1);
}

while(1) {
     fread(&curr, sizeof(FLUG), 1, fp);
     printf("\n%d", curr->flugnummer);
     //fluege_sortieren(curr);
}
}

I get the error when I try to print out curr->flugnummer.

Ok so I changed the two functions a little, but it still doesn't seem to work. I'm sorry, I don't seem to get it...

[EDIT2] Another version that doesn't work:

void fluege_laden() {
    ELEM_ZGR curr;  // <<<- allocate an actual struct here rather than just a pointer
    FILE *fp;

    int i = 0;
    curr = first;

    if (fopen_s(&fp, datei,"rb") != 0) {
        printf("\nDatei %s nicht zum Lesen zu oeffnen",datei);
        PAUSE;
        exit(1);
    }

    while(1) {
        fread(curr, sizeof(FLUG), 1, fp);
        printf("\n%d", curr->flugnummer);   // <<<
        printf("\n%s", curr->flugziel);
        //fluege_sortieren(curr);
        PAUSE;
    }

}

int fluege_sichern() {
ELEM_ZGR curr;
FILE *fp;

curr = first;

if (fopen_s(&fp, datei,"a+b") != 0) {
    printf("\nDatei %s nicht zum Anhaengen zu oeffnen",datei);
    PAUSE;
    exit(1);
}

for(curr = first; curr != NULL; curr = curr->next) {
    fwrite(curr, sizeof(FLUG), 1, fp);
}

    fclose(fp);
    return 1;
}

Upvotes: 2

Views: 3329

Answers (4)

hmjd
hmjd

Reputation: 122011

curr is an uninitialised pointer (a FLUG*) and is therefore not pointing to valid memory when fread() is called. Writing to invalid memory is undefined behaviour (the program could seg fault or execute incorrectly or worst case execute correctly). Either create a stack allocated object (of type FLUG) or dynamically allocate memory for curr.

Personally, I find it very confusing when a pointer is typedefd as at the point of use it is not obvious that the variable is a pointer:

ELEM_ZGR curr;

The following is unambiguous:

FLUG* curr; /* Or just 'FLUG curr;' for this case. */

Check the result of fread() to ensure the program is not operating on stale data:

FLUG curr;
while (1 == fread((&curr, sizeof(FLUG), 1, fp))
{
    printf("\n%d", curr.flugnummer);
}

(In response to the question edit)

In short, change:

fwrite(curr, sizeof(FLUG*), 1, fp);
fread(&curr, sizeof(FLUG*), 1, fp);

to:

fwrite(curr, sizeof(FLUG), 1, fp);
fread(curr, sizeof(FLUG), 1, fp);

In both cases, curr is a FLUG* and is pointing to valid memory for storing a FLUG so you need to read the sizeof(FLUG), not the sizeof(FLUG*). The typical size for a pointer of any type is 4 or 8 bytes. On my x86 box it is 4 bytes and the size of a FLUG is 88 bytes. The size argument to both fwrite() and fread() instructs the number of bytes to read and write:

fwrite(curr, sizeof(FLUG), 1, fp); /* write 88 bytes to fp from address curr. */
fread(curr, sizeof(FLUG), 1, fp); /* read 88 bytes from fp and write to the
                                     address beginning at curr. */

Passing the address of &curr to fread() means a FLUG** is being passed to fread() which is incorrect.

Upvotes: 3

Paul R
Paul R

Reputation: 213200

In the read routine ELEM_ZGR curr; is just an uninitialised pointer. You need to do something like this:

void fluege_laden() {
    FLUG curr;  // <<<- allocate an actual struct here rather than just a pointer
    FILE *fp;
    int i = 0;

    if (fopen_s(&fp, datei,"rb") != 0) {
        printf("\nDatei %s nicht zum Lesen zu oeffnen",datei);
        PAUSE;
        exit(1);
    }

    while(1) {
        fread(&curr, sizeof(FLUG), 1, fp); // <<<
        printf("\n%d", curr.flugnummer);   // <<<
        //fluege_sortieren(curr);
    }
}

Also, in the write routine you need to write the whole struct, e.g.

int fluege_sichern() {
    ELEM_ZGR curr;
    FILE *fp;
    char* tag;

    curr = first;

    if (fopen_s(&fp, datei,"a+b") != 0) {
        printf("\nDatei %s nicht zum Anhaengen zu oeffnen",datei);
        PAUSE;
        exit(1);
    }

    for(curr = first; curr != NULL; curr = curr->next) {
        fwrite(curr, sizeof(FLUG), 1, fp); // <<<- curr is already a pointer - do not dereference here !
    }

    fclose(fp);
    return 1;
}

Upvotes: 2

cdarke
cdarke

Reputation: 44434

You are writing pointers to a file, called a shallow copy. Pointers are not transferable, you need to write code to do a deep copy. Either that, or use something like JSON or YAML.

Upvotes: 0

Nicholas Wilson
Nicholas Wilson

Reputation: 9696

Whoa! Think what memory you're reading into there. Your fread is asking for data to get dumped in some random location (because curr is uninitialised, so points to memory that probably doesn't exist in your process). You need to allocate some FLUGs and read into them.

Another problem is that you shouldn't be writing pointers to file; the data only has meaning within your process. When you read back the FLUGs, at the very least, you should set cur->next to something sensible (like the next FLUG!).

Upvotes: 2

Related Questions