Write an array data structure to file in C

Serializing our array data structure

In regard to the previous article on creating a dynamic array data structure, I am showing you a small example on saving the array to disk, in a binary file, then read it and load it again in a new data structure.

So, I highly recommend to click on the article link above, see how the whole code looks until now so you can have a better understanding.

The struct I use as array elements is this one. As you can see it has a char* member so writing in a single

fwrite

line is troublesome.

struct MyData {
    char* name;
    int value;
};

Instead we will write each member individually, even more than that, we will write the size of the array at the beginning of the file so we don’t have to specify it when loading.

The serialization function

The function takes an array data structure, it’s size and the filename as parameters. It creates a new file based on the name you specify, then first writes the size of the array as an int, then after, it goes through the entire array, visiting each struct and writing to file it’s members (name and value).

Mind the fact that because char* name is a pointer, we had to first evaluate the reference

(&arrayStructure[i])

then call the arrow operator

->

on it.

void serialize(MyData* arrayStructure, int arraySize, const char* filename) {
    /* we open the file to write binary */
    FILE* file = fopen(filename, "wb");
    if (file == 0) {
        return void();
    }
    int i;

    /* write array size */
    fwrite(&arraySize, sizeof(int), 1, file);

    /* go through array and write each property of the struct file */
    for (i = 0; i name, 25 * sizeof(char), 1, file);
	fwrite(&arrayStructure[i].value, sizeof(int), 1, file);
    }

    /*close the file */
    fclose(file);
}
The deserialization function

This one takes only two parameters, the name of the file which contains the previously saved array structure and an int* pointer so we can have two return values. You don’t need to know the size of the array when reading it from the disk (that’s why we first write the size in the serialization function) but you need to know it’s size after when you probably want to go through all elements and display them. That’s why you need to create and int and pass it’s reference to the function so it can return both the array and it’s size.

MyData* deserialize(const char* filename, int* size) {
    /* we open the file to read binary */
    FILE* file = fopen(filename, "rb");
    if (file == 0) {
        return NULL;
    }
    int arraySize = 0;

    /* we read the first int to know how large the array is*/
    fread(&arraySize, sizeof(int), 1, file);

    /* initialize one to store it */
    MyData* newArray = createArray(arraySize);
    int i; 

    /* go through each record, create struct and insert it */
    for (i = 0; i < arraySize; i++) {
        MyData data;
	data.name = (char*)calloc(25, sizeof(char));
	data.value = 0;
	fread(data.name, 25 * sizeof(char), 1, file);
	fread(&data.value, sizeof(int), 1, file);
	insert(&newArray, data, i, arraySize);
    }

    /* size is a pointer so we can have two return values */
    *size = arraySize;

    /* close the file and return the array data structure */
    fclose(file);
    return newArray;
}
Main function example

Here we are testing the code:

int main() {	
    const int ARRAY_SIZE = 7;
    MyData* testArray = createArray(ARRAY_SIZE);
    int i;

    /* initializing with some data */
    for (i = 0; i < ARRAY_SIZE; i++) {
	testArray[i].value = i + 1;
	testArray[i].name = (char*)calloc(25, sizeof(char));
	strcpy(testArray[i].name, "serialization test");
    }

    /* writing to file */
    serialize(testArray, ARRAY_SIZE, "file.bin");

    int size;
    /* passing size as a reference so the function will write at 
    its memory location the actual value of the array read from the file */
    MyData* final = deserialize("file.bin", &size);
    for (i = 0; i < size; i++) {
	printf("Deserialized: %s %d\n", final[i].name, final[i].value);
    }
    return 0;
}

The output is

Deserialized: serialization test 1
Deserialized: serialization test 2
Deserialized: serialization test 3
Deserialized: serialization test 4
Deserialized: serialization test 5
Deserialized: serialization test 6
Deserialized: serialization test 7

Changing the value of ARRAY_SIZE to 19 and running the program again we see the following output

Deserialized: serialization test 1
Deserialized: serialization test 2
Deserialized: serialization test 3
Deserialized: serialization test 4
Deserialized: serialization test 5
Deserialized: serialization test 6
Deserialized: serialization test 7
Deserialized: serialization test 8
Deserialized: serialization test 9
Deserialized: serialization test 10
Deserialized: serialization test 11
Deserialized: serialization test 12
Deserialized: serialization test 13
Deserialized: serialization test 14
Deserialized: serialization test 15
Deserialized: serialization test 16
Deserialized: serialization test 17
Deserialized: serialization test 18
Deserialized: serialization test 19

So it definitely works!

To see more about writing structs to file, especially those that containing char* or other kind of pointers, please look at this article as well.

FacebookTwitterLinkedin