2

I have an array, which holds 6 words and a secret word

char boardInputs[7][6];

I need to autosave to binary file this array every time when user entered the word. After restarting the program, I need to read the saved array of words from the binary file and install it into the input data array of the board

void readArray(int rows, int cols, char array[rows][cols]) {
    FILE *data;
    data = fopen("autosave.bin", "rb");
    fread(array, sizeof(char[rows][cols]), 1, data);
}


void autoSave() {
    int result = EXIT_SUCCESS;
    char file_name[] = "autosave.bin";
    FILE *fp = fopen(file_name, "wb");
   
    if (fp == NULL) {
        result = EXIT_FAILURE;
        fprintf(stderr, "fopen() failed for '%s'\n", file_name);
    } else {
        size_t element_size = sizeof *boardInputs;
        size_t elements_to_write = sizeof boardInputs;
        size_t elements_written = fwrite(boardInputs, element_size, elements_to_write, fp); 
        if (elements_written != elements_to_write) {
            result = EXIT_FAILURE;
            fprintf(stderr, "fwrite() failed: wrote only %zu out of %zu elements.\n", 
                    elements_written, elements_to_write);
        }

        fclose(fp);
    }
}

int main() {
    int cols = 7;
    int rows = 6;
    char (*myArray)[cols] = allocArray(rows, cols);

    readArray(rows, cols, myArray);
    strcpy(boardInputs, myArray);
    free(myArray);
}

I created this code, but the words from the binary file are set incorrectly. How to fix it?

1
  • You should close data in readArray(). Please update question to make it a minimal reproducible example. It's close but missing headers and example data (or rewrite it so it first saves some hard-coded data then reads it back) to demonstrate what the issue is. Commented May 15, 2022 at 9:26

2 Answers 2

2

There are multiple problems in your code:

  • you do not test for fopen() failure in readArray;
  • you do not close the file in read_array;
  • result is unused in autoSave;
  • strcpy is incorrect to copy the whole board. You should test if readArray succeeded and use memcpy;
  • the sizes in autoSave are incorrect: size_t element_size = sizeof *boardInputs evaluates to the size of a word, ie 6 bytes, and size_t elements_to_write = sizeof boardInputs is the size in bytes of the whole array. fwrite will attempt to write 6 * 42 bytes, causing undefined behavior as it accesses boardInputs beyond its boundaries. The length of an array is its size divided by the element size. In this case, it is probably best to use bytes, not words as the unit;
  • to ensure consistency between boardInputs and myArray, they should be defined with the same size by construction.

Here is a modified version:

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

#define WORD_COUNT 7
#define WORD_LEN   6
char boardInputs[WORD_COUNT][WORD_LEN];
const char *autoSaveFilename = "autosave.bin";

int readArray(int rows, int cols, char array[rows][cols]) {
    FILE *fp = fopen(autoSaveFilename, "rb");
    if (fp == NULL)
        return -1;
    int n = fread(array, sizeof(char[rows][cols]), 1, fp);
    fclose(fp);
    return n == 1 ? 0 : -1;
}

int autoSave(void) {
    int result = EXIT_SUCCESS;
    FILE *fp = fopen(autoSaveFilename, "wb");
   
    if (fp == NULL) {
        result = EXIT_FAILURE;
        fprintf(stderr, "fopen() failed for '%s': %s\n",
                autoSaveFilename, strerror(errno));
    } else {
        size_t element_size = 1;
        size_t elements_to_write = sizeof(boardInputs);
        size_t elements_written = fwrite(boardInputs, 1, elements_to_write, fp); 
        if (elements_written != elements_to_write) {
            result = EXIT_FAILURE;
            fprintf(stderr, "fwrite() failed: wrote only %zu bytes out of %zu.\n", 
                    elements_written, elements_to_write);
        }
        fclose(fp);
    }
    return result;
}

int main() {
    char myArray[WORD_COUNT][WORD_LEN];

    if (!readArray(WORD_COUNT, WORD_LEN, myArray))
        memcpy(boardInputs, myArray, sizeof boardInputs);

    return 0;
}
Sign up to request clarification or add additional context in comments.

Comments

1
  1. autoSave() is calling fwrite() with incorrect arguments, sizeof boardInputs is the total size of the 2d array so number of elements is 1. This was the key issue.
  2. autoSave() doesn't return anything so eliminate result.
  3. autoSave() and readArray() hard-code the same path, so make it a define instead of duplication.
  4. readArray() relies on a global variable, so elevated rows and cols to macro constants and simplified number of arguments.
  5. readArray() should close the data file handle.
  6. main() should return an int.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ROWS 7
#define COLS 6
#define PATH "autosave.bin"
char boardInputs[ROWS][COLS];

void autoSave() {
    FILE *fp = fopen(PATH, "wb");
    if(!fp) {
        fprintf(stderr, "fopen() failed for '%s'\n", PATH);
        return;
    }
    size_t elements_to_write = sizeof boardInputs;
    size_t elements_written = fwrite(boardInputs, 1, elements_to_write, fp);
    if (elements_written != elements_to_write) {
        fprintf(stderr, "fwrite() failed: wrote only %zu out of %zu elements.\n",
            elements_written, elements_to_write);
    }
    fclose(fp);
}

void printArray(char array[ROWS][COLS]) {
    for(int i = 0; i < ROWS; i++) {
        printf("%d: %s\n", i, array[i]);
    }
}

void readArray(char array[ROWS][COLS]) {
    FILE *data = fopen(PATH, "rb");
    fread(array, sizeof(char[ROWS][COLS]), 1, data);
    fclose(data);
}


int main() {
    for(unsigned i = 0; i < 7; i++) {
        char s[7];
        sprintf(s, "%u", i);
        strcpy(boardInputs[i], s);
    }
    printArray(boardInputs);
    autoSave();
    char myArray[ROWS][COLS];
    readArray(myArray);
    printArray(myArray);
    return 0;
}

The output demonstrate the read and write have the same values:

0: 0
1: 1
2: 2
3: 3
4: 4
5: 5
6: 6
0: 0
1: 1
2: 2
3: 3
4: 4
5: 5
6: 6

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.