Search code examples
carraysstaticmallocmisra

How to include a variable-sized array as stuct member in C?


I must say, I have quite a conundrum in a seemingly elementary problem. I have a structure, in which I would like to store an array as a field. I'd like to reuse this structure in different contexts, and sometimes I need a bigger array, sometimes a smaller one. C prohibits the use of variable-sized buffer. So the natural approach would be declaring a pointer to this array as struct member:

struct my {
    struct other* array;
}

The problem with this approach however, is that I have to obey the rules of MISRA-C, which prohibits dynamic memory allocation. So then if I'd like to allocate memory and initialize the array, I'm forced to do:

var.array = malloc(n * sizeof(...));

which is forbidden by MISRA standards. How else can I do this?


Solution

  • Edit: This solution does not conform to MISRA-C rules.

    You can kind of include VLAs in a struct definition, but only when it's inside a function. A way to get around this is to use a "flexible array member" at the end of your main struct, like so:

    #include <stdio.h>
    struct my {
      int len;
      int array[];
    };
    

    You can create functions that operate on this struct.

    void print_my(struct my *my) {
      int i;
      for (i = 0; i < my->len; i++) {
        printf("%d\n", my->array[i]);
      }
    }
    

    Then, to create variable length versions of this struct, you can create a new type of struct in your function body, containing your my struct, but also defining a length for that buffer. This can be done with a varying size parameter. Then, for all the functions you call, you can just pass around a pointer to the contained struct my value, and they will work correctly.

    void create_and_use_my(int nelements) {
      int i;
    
      // Declare the containing struct with variable number of elements.
      struct {
        struct my my;
        int array[nelements];
      } my_wrapper;
    
      // Initialize the values in the struct.
      my_wrapper.my.len = nelements;
      for (i = 0; i < nelements; i++) {
        my_wrapper.my.array[i] = i;
      }
    
      // Print the struct using the generic function above.
      print_my(&my_wrapper.my);
    }
    

    You can call this function with any value of nelements and it will work fine. This requires C99, because it does use VLAs. Also, there are some GCC extensions that make this a bit easier.

    Important: If you pass the struct my to another function, and not a pointer to it, I can pretty much guarantee you it will cause all sorts of errors, since it won't copy the variable length array with it.