Can we have a structural element of type Variable length array?

Can we declare a structural 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; 
+6
source share
5 answers

If the encoding is in C99 or C11, you can use the flexible elements of the array (you do not give an explicit dimension, but you should have an agreement on this at runtime in your head).

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

For any array, each slot of a flexible array element has a fixed size. I use a pointer (e.g. 8 bytes on my Linux / x86-64 machine).

(In older compilers, before C99 standards, you can try to give a size of 0 , for example char* Employee_Names[0]; even if it is against the standard)

Then you should highlight such a structure using, for example,

  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 can use (with strdup (3) duplicating the line on 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 will need the function void destroy_employee(st_employee*e) (on the left as an exercise for the reader). Probably it should go through i to free every e->Employee_Names[i] , then free(e); ...

Remember to document the memory usage agreements (who is responsible for calling malloc and free ). Read more about C dynamic memory allocation (and fear memory fragmentation and buffer overflows and any other undefined behavior ).

If you use GCC older than GCC 5, you must compile with gcc -std=c99 -Wall , since the standard standard for older GCC 4 compilers is C89. For new compilers, request all warnings and many others, for example. gcc -Wall -Wextra ...

+8
source

TL DR answer - No, you cannot.

To clarify, let me quote C11 , chapter Β§6.7.2.1, Structure and union specifiers (emphasis added)

An element of a structure or union can have any complete type of an object , other than a modified type. [...]

and, VLA is a modified type.

However, referring to the same standard regarding a flexible array element

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

So you can do something like

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

and then you can dynamically allocate memory at runtime to Employee_Names (and Employee_Names[i] too) and use it.

+6
source

As far as I understand, this is impossible; it is impossible to have one structure field defined in terms of another field.

+1
source

NO,

When you define a structure, its size must be confirmed, so when you declare a variable of this type of structure, memory can be allocated for this variable.

Think about this scenario. If you want to declare a variable p type st_employees , since No_Of_Employees has not yet been set, the size of the variable p not confirmed, so the memory for the variable cannot be allocated. But you cannot set No_Of_Employees without declaring a variable of type st_employees . This is a paradox.

+1
source

You can do this with dynamic allocation as follows:

 #include <stdio.h> #include <stdlib.h> #define SIZE_OF_ELEM 15 #define uint8_t char typedef struct { uint8_t No_Of_Employees; uint8_t **Employee_Names; }st_employees; int main() { int i; st_employees emps; emps.No_Of_Employees = 2; //number of elements // allocate the number of elements emps.Employee_Names = malloc(emps.No_Of_Employees); for (i=0; i < emps.No_Of_Employees; i++) { // allocate each element emps.Employee_Names[i] = malloc(SIZE_OF_ELEM); // fill the element with some data sprintf(emps.Employee_Names[i], "emp_n%d", i); } // show the content for (i=0; i<emps.No_Of_Employees; i++) { printf("Employee %d content: %s\n", i, emps.Employee_Names[i]); } return 0; } 

Of course, this is an illustration, you need to check the distribution, specify the size and type of memory.

Note that this method allows you to create a collection of objects that can have different types, and there is no need to use any specific version or C compiler options.

However, in a very basic case (as in the OP example), this is not the best solution, since it will fragment memory (one allocation per object). Therefore use this with caution.

0
source

All Articles