1

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.

  • 6
    `db->employee` is a pointer, writing its address to a file (and then attempting to read it back) will not lead to anything good happening – UnholySheep Apr 27 '23 at 15:01
  • 5
    Writing structures containing pointers into a file doesn't make sense. – Jabberwocky Apr 27 '23 at 15:01
  • Why is the choice between saving and loading done with `#ifdef`? It would make more sense for it to be a command-line option or a prompt. – Barmar Apr 27 '23 at 15:10
  • Also, I don't see the point in using conditional compilation to determine read vs write. Then you have to recompile each time. pass in a command line argument instead to determine which action to take, – OldProgrammer Apr 27 '23 at 15:11
  • [don't cast malloc](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – Barmar Apr 27 '23 at 15:57
  • Apart from the problems caused by apointer in the structure, saving/restoring data structures by writing/reading the binary representation might be problematic. The binary representation might not be the same on different platforms or different compiler versions or even different compiler settings. Read about [Serialization](https://en.wikipedia.org/wiki/Serialization), https://stackoverflow.com/q/6002528/10622916 – Bodo Apr 27 '23 at 16:11

1 Answers1

4

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)
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Nice, this is definitely one of the problems and most important one. Unfortunately, this makes the program correct but for me there are still those error appears frequently, I am unable to understand the reason, but could you inspect those free( ) statements and help me out. – Rakesh Solanki Apr 27 '23 at 15:54
  • @RakeshSolanki ask a new question about that other problem. – Jabberwocky Apr 27 '23 at 15:55
  • @RakeshSolanki I don't see anything obviously wrong with the `free()` statements. – Barmar Apr 27 '23 at 15:57
  • @RakeshSolanki The problem is your `sizeof` in the `malloc()` calls. I've updated the answer. – Barmar Apr 27 '23 at 15:59
  • Yes that last correction cleaned the program. Now its working correctly, thanks for your help. Most part it seems I understand pointers, malloc, free but often it confuses, and to make it worse errors because violent and random in the case. You people make me going. THANK YOU. – Rakesh Solanki Apr 27 '23 at 16:13