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

大憨熊 提交于 2019-12-29 05:25:12

问题


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;

回答1:


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...




回答2:


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.




回答3:


To my understanding, this is not possible; it is impossible to have one field of a struct defined in terms of a different field.




回答4:


NO,

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

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




回答5:


You can do this with dynamic allocation as follow:

#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 have to check allocation, precise the sizeof type and release memory.

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

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



来源:https://stackoverflow.com/questions/32311269/can-we-have-a-struct-element-of-type-variable-length-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!