Search code examples
arrayscdata-structuresbinary-datafile-writing

Unexpected behavior in Visual C when writing and reading binary file with struct data


I am hanging on this problem since morning and found no solution. Also it gives various errors like, TESTING.exe has triggered a breakpoint, previously it was complaining about heap corruption other time it was cannot write data etc. I am using visual studio 2017 IDE, but using only basic C functions. If anyone can point out errors It will be highly helpful for me. Here is the code:

#define _CRT_SECURE_NO_WARNINGS

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

#define SAVE

typedef struct Employee
{
    char id[6];         
    char surname[20];
    char lastname[20]; 
    char firstname[20];
    unsigned int basic;
    unsigned int incentive;
    unsigned int salary;

} Employee;


typedef struct Database
{
    Employee* employee;
    unsigned int size;

} Database;

int SaveDatabase(const char* fileName, Database* db)
{
    FILE* fp = fopen(fileName, "wb");

    if (fp == NULL)
        return 1;

    if (fwrite(&db->size, sizeof(db->size), 1, fp) != 1)
    {
        fclose(fp);
        return 2;
    }

    if (fwrite(&db->employee, sizeof(db->employee), db->size, fp) != db->size)
    {
        fclose(fp);
        return 3;
    }

    fclose(fp);
    return 0;
}

Database* LoadDatabase(const char* fileName)
{
    Database* db = (Database*)malloc(sizeof(Database));

    unsigned int n = 0;

    FILE* fp = fopen(fileName, "rb");

    if (fread(&n, sizeof(n), 1, fp) != 1)
    {
        fclose(fp);
        return NULL;
    }

    db->employee = (Employee*)malloc(n * sizeof(db->employee));

    if (fread(&db->employee, sizeof(db->employee), n, fp) != n)
    {
        fclose(fp);
        return NULL;
    }

    fclose(fp);
    return db;
}

int main(int argc, char* argv[])
{

#ifdef SAVE

    Database* db = (Database*)malloc(sizeof(Database));
    db->size = 2;
    db->employee = (Employee*)malloc(db->size * sizeof(db->employee));

    strcpy(db->employee[0].id, "1234");
    strcpy(db->employee[0].surname, "Bakshi");
    strcpy(db->employee[0].lastname, "Vipin");
    strcpy(db->employee[0].firstname, "Byomkesh");
    db->employee[0].basic = 25000;
    db->employee[0].incentive = 25000;
    db->employee[0].salary = 50000;

    strcpy(db->employee[1].id, "1235");
    strcpy(db->employee[1].surname, "Chatterjee");
    strcpy(db->employee[1].lastname, "Naren");
    strcpy(db->employee[1].firstname, "Basu");
    db->employee[1].basic = 35000;
    db->employee[1].incentive = 30000;
    db->employee[1].salary = 65000;


    SaveDatabase("Data.dat", db);
    free(db->employee);
    free(db);

#else

    // loading database

    Database* db = LoadDatabase("Data.dat");

    for (unsigned int i = 0; i < db->size; i++)
    {
        printf("\n%s/t%s %s %s %u %u %u", db->employee[i].id, db->employee[i].firstname, db->employee[i].lastname, db->employee[i].surname
            , db->employee[i].basic, db->employee[i].incentive, db->employee[i].salary);
    }

    free(db->employee);
    free(db);

#endif // SAVE

    return 0;
}

At the first instance with SAVE macro defined it should save data to binary file and when SAVE is not defined than it will read from binary file and show the data.


Solution

  • db->employee is a pointer. Writing this pointer to the file doesn't save the contents of the array.

    Don't take the address of db->employee, use it as the pointer to the buffer you want to write or read:

    fwrite(db->employee, sizeof(*db->employee), db->size, fp)
    

    And conversely, when reading:

    fread(db->employee, sizeof(*db->employee), n, fp)
    

    Another problem. db->employee is a pointer, so sizeof(db->employee) is the size of a pointer, not the size of the structure. Change your malloc calls to:

    malloc(db->size * sizeof(*db->employee)