Ex17, line 44 fread returning zero. Don't know why

Hello,
I am having the same problem as here: Ex17: fread returns 0 at line 44

Here is my code:

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

#define MAX_DATA 512
#define MAX_ROWS 100

struct Address {
    int id;
    int set;
    char name[MAX_DATA];
    char email[MAX_DATA];
};

struct Database {
    struct Address rows[MAX_ROWS];
};

struct Connection {
    FILE *file;
    struct Database *db;
};

void err_msg(const char *message)
{
    if (errno) {
        perror(message);
    } else {
        printf("ERROR: %s\n", message);
    }

    exit(1);
}

void Address_print(struct Address *addr)
{
    printf("%d %s %s\n", addr->id, addr->name, addr->email);
}

void Database_load(struct Connection *conn)
{
    printf("Attempting to load database from file stream @: %p\n", conn->file);
    int rc = fread(conn->db, sizeof(struct Database), 1, conn->file);
    printf("return code is %d\n", rc);
    if (rc != 1) {
        printf("%d\n", errno);
        err_msg("Failed to load database.");
    }
}

struct Connection *Database_open(const char *filename, char mode)
{
    printf("opening database with filename: %s\n", filename);
    struct Connection *conn = malloc(sizeof(struct Connection));
    if (!conn)
        err_msg("Memory error");

    conn->db = malloc(sizeof(struct Database));
    if (!conn->db)
        err_msg("Memory error");

    if (mode == 'c') {
        conn->file = fopen(filename, "w");
    } else {
        conn->file = fopen(filename, "r+");

        if (conn->file) {
            printf("The connection's file is: %p\n and its database is at %p\n", conn->file, conn->db);
            Database_load(conn);
        }
    }

    if (!conn->file)
        err_msg("Failed to open the file.");

    return conn;
}

void Database_close(struct Connection *conn)
{
    if (conn) {
        if (conn->file)
            fclose(conn->file);
        if (conn->db)
            free(conn->db);
        free(conn);
    }
}

void Database_write(struct Connection *conn)
{
    rewind(conn->file);

    int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
    if (rc != 1)
        err_msg("Failed to write to database.");

    rc = fflush(conn->file);
    if (rc == -1)
        err_msg("Cannot flush database.");
}

void Database_create(struct Connection *conn)
{
    int i = 0;

    for (i = 0; i < MAX_ROWS; i++) {
        // make a prototype to initialize it
        struct Address addr = {.id = i,.set = 0 };
        // then just assign it
        conn->db->rows[i] = addr;
        // Address_print(&conn->db->rows[i]);
    }
}

void Database_set(struct Connection *conn, int id, const char *name,
        const char *email)
{
    struct Address *addr = &conn->db->rows[id];
    if (addr->set)
        err_msg("Already set, delete it first.");

    addr->set = 1;
    // WARNING: bug, read the 'how to break it' and fix this
    char *res = strncpy(addr->name, name, MAX_DATA);
    // demonstrate the bug
    if (!res)
        err_msg("Name copy failed.");

    res = strncpy(addr->email, email, MAX_DATA);
    if (!res)
        err_msg("email copy failed.");
}

void Database_get(struct Connection *conn, int id)
{
    struct Address *addr = &conn->db->rows[id];

    if (addr->set) {
        Address_print(addr);
    } else {
        err_msg("ID not set");
    }
}

void Database_delete(struct Connection *conn, int id)
{
    struct Address addr = {.id = id,.set = 0 };
    conn->db->rows[id] = addr;
}

void Database_list(struct Connection *conn)
{
    int i = 0;
    struct Database *db = conn->db;

    for (i = 0; i < MAX_ROWS; i++) {
        struct Address *cur = &db->rows[i];

        if (cur->set) {
            Address_print(cur);
        }
    }
}

int main(int argc, char *argv[])
{
    if (argc < 3)
        err_msg("USAGE: ex17 <dbfile> <action> [action parameters]");

    char *filename = argv[1];
    printf("filename is %s\n", filename);
    char action = argv[2][0];
    struct Connection *conn = Database_open(filename, action);
    int id = 0;

    if (argc > 3) id = atoi(argv[3]);
    if (id >= MAX_ROWS) err_msg("There's not that many records.");

    switch (action) {
        case 'c':
            Database_create(conn);
            Database_write(conn);
            break;

        case 'g':
            if (argc != 4)
                err_msg("Need an id to get.");

            Database_get(conn, id);
            break;

        case 's':
            printf("Setting data.");
            if (argc != 6)
                err_msg("Need id, name, email to set");

            Database_set(conn, id, argv[4], argv[5]);
            Database_write(conn);
            break;

        case 'd':
            if (argc != 4)
                err_msg("Need id to delete.");

            Database_delete(conn, id);
            Database_write(conn);
            break;

        case 'l':
            printf("Attempting to list database.");
            Database_list(conn);
            break;
        default:
            err_msg("Invalid action: c=create, g=get, s=set, d=del, l=list");
    }

    Database_close(conn);

    return 0;
}

which I have diffed with the version on the github. It differs in no regards other than I changed the name of die to err_msg and have added some debug printfs. Everything else is the same.

When the main function tries to open the database, it fails. The print statements allowed me to localise the error to fread, which returns a return code of zero, man says this means either end of file or an error.

Any help or hints would be gladly appreciated.
Many thanks.

Don’t know if you still are looking for the answer, but, in my experience, that means the file has not been written to, at all. So probably the writes are failing when the database is created. Or, you’re attempting to call some other function before calling the ‘c’ option?

Hi, thanks for the reply. I ended up ‘solving’ the issue by switching to Ubuntu and everything worked there - I’d wanted to switch for a long time anyway. Not sure why I couldn’t get identical code to work on Windows, probably weird reasons.

I’m shutting down this forum so please direct future help requests to the Discord or help@learncodethehardway.com.