Gary
Gary

Reputation: 2859

How to allocate memory for a struct with a member of unknown variable size?

Somebody kindly helped me a couple days ago with a large part of this in another SO question. At that time, the size of struct base was known in advance. I'd like to alter member path to be a character array the size of which isn't known until right before allocating memory for a new instance of base in the base_new() function.

In the previous version, all files were required to be stored in the same directory and only the file name was added; and it was limited to length 256. Now I'd like to permit user added subdirectories under the ../../databases directory and not limit the length.

Is it possible to set the size of path before or after the db[i] = malloc( sizeof ( struct base ) ) in base_new()?

Or, perhaps, I should simply ask, how can this be accomplished?

Thank you.

/* Global declaration */
struct base {
 ...
 char path[];
};

struct base **db;

/* in main() */
db = malloc( n * sizeof *db );
for (size_t i = 0; i < n; ++i)
  db[i] = NULL;

/* Function to assign pointer db[i] to newly allocated struct base */
int base_new( void )
{
  /* declarations */
  // Assign pointer to beginning of memory allocation for the new instance of struct base.
  if ( ( db[i] = malloc( sizeof ( struct base ) ) ) == NULL )
    {
      printf( "Error attempting to malloc space for new base.\n" );
      return 1;
    }

  // When size of path was fixed, just truncated name to 256. */
  l = sizeof( db[i]->path );
  rc = snprintf( db[i]->path, l, "%s%.*s", "../../databases/", 256, name );
  if ( rc > l - 1 || rc < 0 )
    {
      // Not enough space; truncate and add the '\0' at l.
      db[i]->path[l] = '\0';
    }  

  // When size of path variable and writing path. */
  l = sizeof( db[i]->path ) - 16;
  rc = snprintf( db[i]->path, l, "%s%s", "../../databases/", path );
  if ( rc > l - 1 || rc < 0 )
    {
      
      db[i]->path[l] = '\0';
    }  

}

I got a message at the top of my question asking if an existing question answers this one. It is closely related and helpful, but the answer I received here is better I think and discusses a few other related points. I don't know how it is supposed to work but I picked No because this answer is better, or at least I can understand it better. This answer shows how to malloc the variable member of the struct and discusses freeing the memory of the struct by member before freeing the pointer to the struct. The other question is a bit more general but still helpful. Thanks.

Upvotes: 3

Views: 843

Answers (1)

Jarvis
Jarvis

Reputation: 8564

Instead of an array, you can have a pointer inside your struct:

struct base {
    ...
    char *path;
};

Later, allocate memory to this pointer whenever you need it:

base.path = malloc(n * sizeof(char)); // n is the variable size you will set before

Since you allocate memory dynamically now, don’t forget to free to avoid any memory leaks. In C, there is the requirement of every struct having a fixed byte length, so that, for example, sizeof(struct base) can be evaluated at compile time. In your case, the variable length array's size cannot be determined at compile time, so it is illegal do something like char path[l] where l is unknown at compile time.

Btw, a correction regarding

l = sizeof( db[i]->path );

First of all, even if path was declared as an array, this won't give you the size of it in terms of its length, it would return you the complete byte size occupied by the array, you gotta divide it by sizeof (char) to get the length. Now that you have declared it as a pointer however, I guess you don't really need to do this.

Upvotes: 1

Related Questions