cstructdynamic-memory-allocationflexible-array-member

Why can't I reassign flexible array member?


I have the following struct with a flexible array member. However, the code does not compile:

#define INITIAL_CAPACITY 5

typedef struct Object {
   int size;
   int elements[];
} Object;

int main(void) {
  Object* result = calloc(1, sizeof(Object) + sizeof(int)*INITIAL_CAPACITY);
  if (result == NULL) {
    return;
  }

  for (int i = 0; i < INITIAL_CAPACITY; i++) {
    result->elements[i] = 1;
  }

  result->size = INITIAL_CAPACITY;

  int new_size = 2*result->size;
  int* new_elements = calloc(1, sizeof(int)*new_size);
  if (new_elements == NULL) {
     return;
  }

  for (int i = 0; i < INITIAL_CAPACITY; i++) {
    result[i].entries->key = -1;
  }

  result->elements = new_elements; // "error: expression must be modifiable lvalue"
}

Why can't I reassign the flexible array member to a new, larger array?

ps- it compiles if I change the flexible array member to instead read int* elements but I'm not sure why...


Solution

  • A flexible array member is not a pointer, it's part of the original struct. Since you allocated the struct dynamically, you need to use realloc() to enlarge it.

    #define INITIAL_CAPACITY 5
    
    typedef struct Object {
       int size;
       int elements[];
    } Object;
    
    int main(void) {
      Object* result = calloc(1, sizeof(Object) + sizeof(int)*INITIAL_CAPACITY);
      if (result == NULL) {
        return;
      }
    
      result->size = INITIAL_CAPACITY;
    
      int new_size = 2*result->size;
      Object* new_obj = realloc(result, sizeof(Object) + sizeof(int)*new_size);
      if (new_obj == NULL) {
         return;
      }
      result = new_obj;
      // zero out the new allocation, like calloc does
      memset(&new_obj->elements[result->size], 0, sizeof(int)*(new_size - result->size));
      result->size = new_size;
    }