0

EDIT: This can be done by a single execution of fwrite/fread to the nested pointer to struct, as follows:

//write
Path_pointer c;
c.point = (Point*) calloc(2, sizeof(Point));
c.point[0] = (Point){3, 5};
c.point[1] = (Point){-2, 7};
FILE * f = fopen("binary.txt", "wb");
if(f == NULL)  exit(1);
fwrite(c.point, 2*sizeof(Point), 1, f);
fclose(f);

//read
Path_pointer d;
FILE * f = fopen("binary.txt", "rb");
if (f == NULL)  exit(1);
d.point = (Point*) calloc(2, sizeof(Point));
fread(d.point, 2*sizeof(Point), 1, f);
printf("point[0]=(%d,%d)\n", d.point[0].x, d.point[0].y);
printf("point[0]=(%d,%d)\n", d.point[1].x, d.point[1].y);
fclose(f);

I have posted this question because it is different from using pointers in structures to read from file and Writing and reading (fwrite - fread) structures with pointers since:

  • it includes dynamic memory allocation (and in this case the question appears what to put as the second parameter of fwrite and fread).

  • the aforementioned questions did not receive a proper answer with fwrite() and fread() functions.

  • A way to write (using fwrite) to a binary file a struct with a pointer to struct inside, and to read it (using fread) is to do it element by element. My main question is how to write/read such a struct by a single execution of fwrite/fread. This answer cannot be found anywhere in stackoverflow, neither in the two aforementioned posts, nor in any other post.


Original question:

The case with array of struct Point works fine (Path_array), whereas the case with pointer to struct Point does not work (Path_pointer). Perhaps the problem is at the second parameter of functions fwrite() and fread() (i.e., "2*sizeof(Point)").

If I want to write/read a struct like Path_pointer to a binary file, which is the proper way to do it, preferably by a single execution of fwrite/fread?

#include<stdio.h>
#include<stdlib.h>

typedef struct  {
    int x, y;
}Point;

typedef struct  {
    Point point[2];
}Path_array;

typedef struct  {
    Point *point;
}Path_pointer;

FILE * f;

int main()  {

    //--- first case: array of struct Point in Path_array ---
    
    //part 1
    Path_array a;
    a.point[0] = (Point){3, 5};
    a.point[1] = (Point){-2, 7};
    f = fopen("binary_array.dat", "wb");
    if(f == NULL)  exit(1);
    fwrite(&a, sizeof(a), 1, f);
    fclose(f);
    
    //part 2
    Path_array b;
    f = fopen("binary_array.dat", "rb");
    if (f == NULL)  exit(1);
    fread(&b, sizeof(b), 1, f);
    printf("point[0]=(%d,%d)", b.point[0].x, b.point[0].y);
    printf(" and point[1]=(%d,%d)\n",b.point[1].x, b.point[1].y);
    fclose(f);
    
    
    //--- second case: pointer to struct Point in Path_pointer ---
    
    //part 3
    Path_pointer c;
    c.point = (Point*) calloc(2, sizeof(Point));
    c.point[0] = (Point){3, 5};
    c.point[1] = (Point){-2, 7};
    f = fopen("binary_pointer.dat", "wb");
    if(f == NULL)  exit(1);
    fwrite(&c, 2*sizeof(Point), 1, f);
    fclose(f);

    
    //part 4
    Path_pointer d;
    d.point = (Point*) calloc(2, sizeof(Point));
    f = fopen("binary_pointer.dat", "rb");
    if (f == NULL)  exit(1);
    fread(&d, 2*sizeof(Point), 1, f);
    printf("point[0]=(%d,%d)", d.point[0].x, d.point[0].y);
    printf(" and point[1]=(%d,%d)\n",d.point[1].x, d.point[1].y);
    fclose(f);
    
    printf("\n");
    return 0;
}
user3386109
  • 34,287
  • 7
  • 49
  • 68
ckc
  • 345
  • 4
  • 12
  • 1
    You shouldn't save pointers in a file because the next time the program runs, the memory layout may be different, which will make the pointers invalid. That's almost certainly the case with [ASLR](https://en.wikipedia.org/wiki/Address_space_layout_randomization). It can also be the case if you make even the slightest change to the program. – user3386109 Feb 07 '23 at 23:44
  • 1
    *My main question is how to write/read such a struct by a single execution of fwrite/fread. This answer cannot be found anywhere in stackoverflow, neither in the two aforementioned posts, nor in any other post.* That's because it simply can not exist. All C read/write operations read or write contiguous chunks of memory. A pointer in the midst of such a chunk **refers to another chunk**. You're looking for an answer to prove 2+2 = 5. You won't find one. – Andrew Henle Feb 08 '23 at 00:25
  • There is an asnwer: It can be done by a single execution of fwrite/fread to the nested pointer to struct. I have edited the question to include the relevant code. – ckc Feb 08 '23 at 00:53
  • The latest code that you posted **does not** store pointers in the file. If you look at the file with a hex editor, you'll see that it contains `03 00 00 00 05 00 00 00 fe ff ff ff 07 00 00 00`. In other words, it contains the numbers `3, 5, -2, 7`. Those are the values of the two points. It's exactly the same file that the "part1" code creates. – user3386109 Feb 08 '23 at 05:15
  • 1
    You can store the struct with a single `fwrite` because it contains a single pointer, to a single block of memory, that contains all of the data. As soon as you add anything else to the structure, the single `fwrite` won't be possible anymore, [as discussed in this question](https://stackoverflow.com/questions/56149988). – user3386109 Feb 08 '23 at 05:29
  • 1
    @user3386109 You are right on this – ckc Feb 09 '23 at 19:46

1 Answers1

2

you need to think what this :

typedef struct  {
   Point *point;
}Path_pointer;

looks like in memory. The member point contains a pointer, it does not contain a Point. When you write it to a file you are writing a memory address only.

You should start by deciding what you want to data layout in the file to be (generally dumping raw structs toa file is a bad idea). Then write code that write data that way.

NOTE. you are calling the files .txt even though they are not text, it doesnt change the behaviors (the file can be called "an_elehpant_lives.in_my_trousers" if you like) but it will surely confuse people,

pm100
  • 48,078
  • 23
  • 82
  • 145