A fixed length array must be declared with a positive integer constant value in the brackets so that its size may be known at compile-time; note that a const int
is not a compile-time constant, but instead a read-only value. C has had variable length arrays since C99, which can be sized at runtime with variables instead of (compile-time) constants. If the posted code was compiled under C99, then this was interpreted as a VLA:
char level_data[get_terminal_size()];
VLAs were made optional in C11, but they appear to be well-supported in most C11 implementations. Under C89, the above declaration would raise an error since there is no support for VLAs here. But in more modern C implementations that support VLAs, the problem is that a struct
can not contain a VLA member.
With Dynamic Allocation
To obtain an array member in a struct
that has its length determined at runtime, you could use either a pointer to dynamically allocated memory, or a flexible array member. A flexible array member is an incomplete array type declared as the last member of a struct
with more than one named member. The size of such a struct
is calculated as if the FAM were omitted:
struct level {
int id;
size_t data_sz;
char level_data[];
};
To use a FAM, you will need to allocate memory for the struct
plus memory for the FAM. You may wish to store the size of the FAM in the struct
, and you will still need to remember to free
the allocation when you are finished with it. Here is an example:
#include <stdio.h>
#include <stdlib.h>
#define DATA_ARRAY_SZ 10;
struct level {
int id;
size_t data_sz;
char level_data[];
};
size_t get_size(void);
int main(void)
{
size_t size = get_size();
struct level *my_level;
my_level = malloc(sizeof *my_level
+ sizeof *my_level->level_data * size);
if (my_level == NULL) {
perror("Unable to allocate memory");
exit(EXIT_FAILURE);
}
my_level->data_sz = size;
for (size_t i = 0; i < my_level->data_sz; i++) {
my_level->level_data[i] = 'a' + i;
}
for (size_t i = 0; i < my_level->data_sz; i++) {
printf("%c", my_level->level_data[i]);
}
putchar('\n');
/* Free allocated memory */
free(my_level);
return 0;
}
size_t get_size(void)
{
return DATA_ARRAY_SZ;
}
Without Dynamic Allocation
If VLAs are available, there is a simpler option that does not require dynamic allocation. You could declare level_data
as a pointer to char
, and declare a VLA of the needed size at runtime, assigning the address of the first element of the VLA to level_data
. Since there is no dynamic allocation, there is nothing to deallocate later. This approach also does not suffer from a limitation of structures with flexible array members: they can't be used as members of other struct
s or arrays.
#include <stdio.h>
#define DATA_ARRAY_SZ 10;
struct level {
int id;
size_t data_sz;
char *level_data;
};
size_t get_size(void);
int main(void)
{
size_t size = get_size();
char data_arr[size];
struct level my_level = { .data_sz = size, .level_data = data_arr };
for (size_t i = 0; i < my_level.data_sz; i++) {
my_level.level_data[i] = 'a' + i;
}
for (size_t i = 0; i < my_level.data_sz; i++) {
printf("%c", my_level.level_data[i]);
}
putchar('\n');
return 0;
}
size_t get_size(void)
{
return DATA_ARRAY_SZ;
}