Home > Blockchain >  How can I save these struct to a binary file?
How can I save these struct to a binary file?

Time:11-08

I have two structs I am aiming to save to a binary file.

typedef struct {
    int height;
    int width;
    int resistance_count;
    Resistance** resistances; //contains a list of resistance*.
} Breadboard;

typedef struct {
    int start_cell_col;
    int end_cell_col;
    int cell_row;
    float resistance_value;
} Resistance;

I am somewhat unsure how I should be going about saving them. Since I need to keep track of the "resistance_count" variable to know how many resistances I will be saving, I have to save the breadboard first. To do that my attempt has been as follows:

bool save_breadboard(char* filename, Breadboard* bb_pointer) {
    errno_t error_code;
    FILE* fp_board;
    
    /* Opens board.bin to save the board struct on. */
    error_code = fopen_s(&fp_board, filename, "wb");
    if (error_code != 0) {
        return false;
    }
    size_t elements_written = fwrite(bb_pointer, sizeof(Breadboard), 1, fp_board);
    if (elements_written == 0) {
        return false;
    }
    fclose(fp_board);
    return true;
}

With my current attempt I see a problem that I am also saving all the "Resistance**" which is perhaps unnecessary. I don't know if there is a way I could skip saving the resistance pointer pointers. But I don't think it will cause problem when I eventually read from it.

To save resistances I'm running into problems. Here is what I do:

bool save_resistances(char* filename, Breadboard* bb_pointer) {
    errno_t error_code;
    FILE* fp_resistances;
    /* Opens resistances.bin to save the array of resistance pointers on. */
    error_code = fopen_s(&fp_resistances, filename, "wb");
    if (error_code != 0) {
        return false;
    }
    size_t elements_written = fwrite(bb_pointer->resistances, sizeof(Resistance),
                                      bb_pointer->resistance_count, fp_resistances);
    if (elements_written == 0) {
        return false;
    }
    fclose(fp_resistances);

    return true;
}

I am pretty sure that I will be saving the resistance pointer this way. I cannot check with binary files, but if I am would dereferencing the resistance pointer help?

size_t elements_written = fwrite(*bb_pointer->resistances, sizeof(Resistance),
                                 ^         bb_pointer->resistance_count, fp_resistances);

Any help in helping me understand reading/writing to binary files would be much appreciated.

CodePudding user response:

You are getting close to the solution. Just a couple of things missing...

With my current attempt I see a problem that I am also saving all the "Resistance**" which is perhaps unnecessary. I don't know if there is a way I could skip saving the resistance pointer pointers [...]

Yeah, it is unnecessary. Indeed when reading back you will have to discard it and overwrite it with a valid value. I wouldn't bother finding strange ways of skipping the pointer. I'd suggest writing out a NULL pointer instead to avoid mistakes when re-reading the data by doing something like:

void *tmp = bb_pointer->resistances;
bb_pointer->resistances = NULL;
size_t elements_written = fwrite(bb_pointer, sizeof(Breadboard), 1, fp_board);
bb_pointer->resistances = tmp;

Now, coming to the part where you actually save all your structures, this is wrong:

size_t elements_written = fwrite(bb_pointer->resistances, sizeof(Resistance),
                                      bb_pointer->resistance_count, fp_resistances);

And doing *bb_pointer->resistances is also wrong. You want to save each Resistance struct, but your ->resistances is an array of pointers, so (1) saving the pointers (bb_pointer->resistances) is obviously wrong and (2) trying to save the structs as if they were contiguous in memory (*bb_pointer->resistances) is also wrong. The only thing you can do is loop over the array and dereference every single pointer, saving it separately:

for (int i = 0; i < bb_pointer->resistance_count; i  ) {
    if (fwrite(bb_pointer->resistances[i], sizeof(Resistance), 1, fp_resistances) != 1) {
        // handle error
        return false;
    }
}

Finally, remember that fwrite returns the number of elements written which should always be equal to the requested number, so in general you need to check for errors with res != count, not with res == 0:

size_t elements_written = fwrite(bb_pointer, sizeof(Breadboard), 1, fp_board);
if (elements_written != 1) {
    return false;
}
  • Related