Tom Kadwill
Tom Kadwill

Reputation: 1478

Dynamically sized structs - Learn C The Hard Way

This is my third question regarding Learn C the Hard Way ex17, I'm getting closer but still haven't solved it :)

I have the following code:

struct Address {
  int id;
  int set;
  char* name;
  char* email;
};

struct Database {
  unsigned int MAX_DATA;
  unsigned int MAX_ROWS;
  struct Address* rows;
};

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

struct Connection *Database_open(const char *filename, char mode)
{
  // struct containing DB struct and DB file
  struct Connection *conn = malloc(sizeof(struct Connection));
  if(!conn) die("Memory error", conn);

  conn->db = malloc(10320);
  if(!conn->db) die("Memory error", conn);

  if(mode == 'c') {
    // truncate file to 0 length and create file for writing
    conn->file = fopen(filename, "w");
  } else {
    // open for reading and writing
    conn->file = fopen(filename, "r+");

    if(conn->file) {
      Database_load(conn);
    }
  }

  if(!conn->file) die("Failed to open file", conn);

  return conn;
}

void Database_write(struct Connection *conn)
{
  // Sets the file position to the beginning of the file?
  rewind(conn->file);

  // writes data to stream
  // fwrite(DB to be written, size of DB row, number of rows, output stream
  int rc = fwrite(conn->db, 10320, 1, conn->file);
  if(rc != 1) die("Failed to write database.", conn);

  // flushed the output buffer. what does this do??
  rc = fflush(conn->file);
  if(rc == -1) die("Cannot flush database.", conn);
}

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

  conn->db->rows = malloc(10320);
  // loop through number of rows and create 'blank rows'
  for(i = 0; i < conn->db->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;
  }
}

I have hard coded some values to try and get it working but Database_create doesn't seem to be creating conn->db struct correctly, like it does with the original code (found here: http://c.learncodethehardway.org/book/ex17.html)

Initially Database_create was erroring so I added the malloc as I thought it was because it needed a block of memory. Can anyone help point out what I am doing wrong? Thanks

Upvotes: 0

Views: 360

Answers (1)

Tim Child
Tim Child

Reputation: 3012

1) malloc rows to be the sizeof(struct address) * MAX_ROWS

conn->db->rows = malloc(sizeof(struct address) * MAX_ROWS);

2) You are creating addr on the stack, when is needs to be allocated or copied, but not assigned.

..
  struct Address addr = {.id = i, .set = 0};
    // then just assign it
    conn->db->rows[i] = addr;
..

So when you leave Database_create the address of addr is invalid.

use

memcpy(conn->db->rows +i, addr, sizeof( struct addr) );

in place of

 conn->db->rows[i] = addr;

Upvotes: 1

Related Questions