2

Does anyone know if there is a way to initialize a structure containing a variable length array without initializing the array first in a separate variable (and without using malloc)?

My structure looks like this:

struct my_struct {
    int *values;
    int size;
}

For now in my code I have that:

void my_function (int size) {
    int values[size];
    struct my_struct mystr = {
        .values = values,
        .size = size
    };
    ...
}

(Array is initialized first, then the structure. This is working but it looks awkward to declare a separate variable for the array.)

This would probably work as well:

void my_function (int size) {
    struct my_struct mystr = { 
        .values = calloc (size, sizeof (int)),
        .size = size
    };
    ...
}

(but I do not want to use mallocs)

But what I would like to write is something like:

void my_function (int size) {
    struct my_struct mystr = { 
        .values = (int[size]){},
        .size = size
    };
    ...
}

Any idea?

FClad
  • 21
  • 2
  • 1
    Do you want to have an array without allocating space for it? – GMichael Jul 22 '16 at 09:50
  • I know I have to allocate space for the array, but I would like to do so without using an intermediate variable such as `int values[size];`. – FClad Jul 22 '16 at 10:03
  • What is wrong with ` .values = calloc (size, sizeof (int)),`? – GMichael Jul 22 '16 at 10:05
  • Dynamic memory allocation is slower and, if you are not careful, can lead to memory leaks. Hence I try to avoid this unless it is absolutely necessary. – FClad Jul 22 '16 at 10:18
  • So initialize the `.values` with NULL and put the real value when you allocate the memory – GMichael Jul 22 '16 at 10:21
  • "*... initialize a structure containing a variable length array*" `int * values;` is a pointer to `int` and not an array, not even a VLA. – alk Jul 22 '16 at 10:24
  • "Dynamic memory allocation is slower..." If this was your rationale for asking this question, it is invalid. Technically speaking, the C standard has no such requirement; VLAs may be implemented internally using `malloc` to save precious *stack space*. Realistically speaking, it should make no significant difference so long as you don't complicate the cache locality. Stop using a pointer to refer to a different chunk of memory, for a start. Use a flexible array member, instead. – autistic Jul 22 '16 at 12:13

2 Answers2

3

First of all, note that you cannot use an array from your stack if you want to return your structure.

int values[size];
struct my_struct mystr = {
    .values = values,
    .size = size
};
return mystr;

This is not going to work since the lifetime of values ends when you return. The same applies if you try to store mystr in a value pointed by a parameter of your function.

Obviously you're not doing that, however I think it's worth to mention anyway.


Answer to your question: it depends on the situation.

Can you be sure that size is small? Or else your stack is going to overflow in int values[size]. Is it small and predictable? Stick with your first solution. If it can be large or dependent on user-input, definitely use malloc.

Are you in some way returning or retaining a persistent pointer to your structure or values? Use malloc (see my first remark).

Alternatively, you can also use the struct hack but then you would have to malloc the entire mystr anyway.


One more thing, you wrote:

(Array is initialized first, then the structure. This is working but it looks awkward to declare a separate variable for the array.)

I'm not sure what you mean, but the int * is only sizeof(intptr_t), irregardless of the size of the array. So you're not allocating twice the memory for 1 array, if that's what you're thinking.

cutsoy
  • 10,127
  • 4
  • 40
  • 57
  • 1
    `sizeof (int *)` is not necessarily equal to `sizeof (intptr_t)`. I think you missed the point; OP isn't concerned about performance or memory use in this question. He/she wants to be more expressive... Those two concepts run orthogonally. – autistic Jul 22 '16 at 11:06
-1

Initializer are unnamed objects initialized by the initializer list. Outside the body of a function, the object has static storage duration. So it is possible to use the address of such an object. With a little help from variadic macros you can try →

 #include <stdio.h>

 struct test {
   int count;
   int *values;
 } test[] = {
 #define init(...) { .count=sizeof( (int[]) {__VA_ARGS__} )/sizeof(int), .values=(int *)&(int []){__VA_ARGS__} }
              init(0,1,2,3,4),
              init(2,4,6,8),
              init(1,3),
              init(42)
            };
 #define test_size ((int) (sizeof test/sizeof *test))

 int main(void)
 {
   for(int array=0; array<test_size; ++array) {
     printf("array %d (%d) : [ ", array+1, test[array].count);
     for(int i=0; i<test[array].count; ++i)
       printf("%d ", test[array].values[i]);
     puts("]");
   }
   return 0;
 }
Picodev
  • 506
  • 4
  • 8