Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can we have a struct element of type Variable length array? [duplicate]

Can we declare a structure element of variable length?

The condition is as follows:

typedef struct
{
   uint8_t No_Of_Employees;
   uint8_t Employee_Names[No_Of_Employees][15];
}st_employees;
like image 896
user12345 Avatar asked Aug 31 '15 12:08

user12345


People also ask

Can a struct variable be an array?

An array can be defined as a data structure where we can group the variables of same data types. Each element of the array can be char, int, double, float or even a structure. We know a structure allows elements of diverse data types to be grouped under a single name.

What is a variable length array in C?

A variable length array, which is a C99 feature, is an array of automatic storage duration whose length is determined at run time.

What is flexible array in C?

A flexible array member is a C99 feature and can be used to access a variable-length object. It is declared with an empty index, as follows: array_identifier[ ]; For example, b is a flexible array member of Foo . struct Foo { int a; int b[]; };


2 Answers

If coding in C99 or C11, you might want to use flexible array members (you don't give an explicit dimension, but you should have a convention about it at runtime in your head).

 typedef struct {
    unsigned No_Of_Employees;
    char* Employee_Names[]; // conventionally with No_of_Employees slots
 }st_employees;

As for any array, each slot of a flexible array member has a fixed size. I'm using a pointer (e.g. 8 bytes on my Linux/x86-64 machine).

(In old compilers before the C99 standards, you might try give a 0 dimension like char* Employee_Names[0]; even if it is against the standard)

Then you would allocate such a structure using e.g.

 st_employees* make_employees(unsigned n) {
    st_employees* s = malloc(sizeof(s_employees)+n*sizeof(char*));
    if (!s) { perror("malloc make_employees"); exit(EXIT_FAILURE); };
    s->No_of_Employees = n;
    for (unsigned i=0; i<n; i++) s->Employe_Names[i] = NULL;
    return s;
 }

and you might use (with strdup(3) duplicating a string in the heap) it like

 st_employees* p = make_employees(3);
 p->Employee_Names[0] = strdup("John");
 p->Employee_Names[1] = strdup("Elizabeth");
 p->Employee_Names[2] = strdup("Brian Kernighan");

You'll need a void destroy_employee(st_employee*e) function (left as an exercise to the reader). It probably should loop on i to free every e->Employee_Names[i], then free(e);...

Don't forget to document the conventions about memory usage (who is in charge of calling malloc and free). Read more about C dynamic memory allocation (and be scared of memory fragmentation and buffer overflows and any other undefined behavior).

If using a GCC older than GCC 5 be sure to compile with gcc -std=c99 -Wall since the default standard for old GCC 4 compilers is C89. For newer compilers, ask for all warnings and more of them, e.g. gcc -Wall -Wextra...

like image 150
Basile Starynkevitch Avatar answered Oct 01 '22 18:10

Basile Starynkevitch


TL;DR answer - No, you cannot.

To elaborate, let me quote C11, chapter §6.7.2.1, Structure and union specifiers (emphasis mine)

A member of a structure or union may have any complete object type other than a variably modified type. [...]

and, a VLA is a variably modified type.

However, quoting from the same standard, regarding the flexible array member

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. [...]

So, you can do something like

typedef struct
{
   uint8_t No_Of_Employees;
   uint8_t* Employee_Names[];
}st_employees;

and later, you can allocate memory dynamically at the runtime to Employee_Names (and Employee_Names[i], too) and make use of it.

like image 22
Sourav Ghosh Avatar answered Oct 01 '22 20:10

Sourav Ghosh