Home > database >  Writing/reading 2D char array in C to binary file
Writing/reading 2D char array in C to binary file

Time:05-16

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?

CodePudding user response:

There are multiple problems in your code:

  • you do not test for fopen() success 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 sizez 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;
}

CodePudding user response:

  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
  •  Tags:  
  • c
  • Related