1

My question is a simple one...I have the following structs declared:

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

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

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

Now having that clear, I initialize my "Database" inside my "Connection" with some dummy Addresses. I later take this database and save it into the file inside my "Connection" struct with:

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

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

   rc = fflush(conn->file);
      if(rc == -1){
         die("Cannot flush database.\n",conn);
      }

Everything works great when I have a predetermined number of rows inside my "Database" struct for my Addresses i.e. 512. But, what if I want to make the number of rows dynamically? As in maybe as a param passed to a function? I have tried using the following...

struct Database {
   struct Address *rows;
};

And allocating space to this pointer with:

conn->db->rows = (struct Address*) malloc(sizeof(struct Address)*max_rows);

With max_rows being a param passed to a function...But, now the problem is that when I go and try to save this to the file inside my "Connection" struct I just save the pointer "struct Address *rows;" and not the data with the space allocated to it. Any suggestions as to how to save this allocated space or have a predetermined array inside a struct and then grow it dynamically?

Thanks in advance!

8
  • 3
    What does your newly updated write code look like that doesn't work? Commented May 9, 2017 at 10:50
  • You have to save the pointer? Were you just dumping the structure to file as bytes? That's a terrible idea. That file is only ever going to be properly read on a subset of machines. What you need is to write a logical representation of the data to file, not just dump bytes as they are in your process's memory. Commented May 9, 2017 at 10:51
  • 2
    You'll have to write some serialization routine which parses the structs. Commented May 9, 2017 at 10:52
  • Do you NEED to cast malloc() to struct Address *? or you just do it because you saw it somewhere else? I am asking this because it would be a lot different if you MUST cast, it would be a whole different language. Also, conn->db->rows might dereference a NULL pointer if you are not careful. And what is die()?, it makes the code look like it's PHP, and it's PHP so, it's PHP. Commented May 9, 2017 at 10:52
  • All my structs are the same with the exception for my "Database" one which I changed to the one I mentioned using the pointer "struct Address *rows" and try to save this with the same "void Database_write" and when I try to open the file of course my data pointed to by my *rows pointer is not there :/ and my die() function is just a general routine to clean up any allocated memory Commented May 9, 2017 at 10:53

1 Answer 1

3

You are on the right track with malloc for creating a dynamic number of Addresses.

conn->db->rows = (struct Address*) malloc(sizeof(struct Address)*max_rows);

But then you have a problem writing them out to file in Database_write. This is because the dynamically-allocated structure no longer has the number of rows hardwired into it. You will have to change Database_write to

  1. Pass in how many rows to write.
  2. Adjust your fwrite line to write out all the rows.

You had:

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

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

You now need something like:

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

    int rc = fwrite(conn->db, sizeof(struct Database), num_rows, conn->file);
    if(rc != num_rows)
    {
        die("Failed to write database.\n",conn);
    }

...

You could also add the number of rows to your database struct to record how many rows are supposed to be in the file:

struct Database 
{
    int num_rows;
    struct Address *rows;
};

In which case you should fwrite the number of rows to file first, then write num_rows of struct Address.

You might also want to look up realloc for changing the number of rows on the fly. Hint - use with care, and pay close attention to the return value.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.