我们可以有一个可变长度数组类型的struct元素吗?
我们可以声明一个可变长度的结构元素吗?
条件如下:
typedef struct { uint8_t No_Of_Employees; uint8_t Employee_Names[No_Of_Employees][15]; }st_employees;
如果在C99或C11中编码,您可能希望使用灵活的数组成员 (您没有给出明确的维度,但是您应该在运行时有一个关于它的约定)。
typedef struct { unsigned No_Of_Employees; char* Employee_Names[]; // conventionally with No_of_Employees slots }st_employees;
对于任何arrays,柔性arrays构件的每个槽具有固定的尺寸。 我正在使用指针(例如我的Linux / x86-64机器上的8个字节)。
(在C99标准之前的旧编译器中,您可以尝试给出像char* Employee_Names[0];
的0
维度char* Employee_Names[0];
即使它违反了标准)
然后你将使用例如分配这样的结构
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; iEmploye_Names[i] = NULL; return s; }
并且您可以使用(使用strdup(3)在堆中复制字符串)
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");
你需要一个void destroy_employee(st_employee*e)
函数(留给读者练习)。 它可能应该循环i
以free
每个e->Employee_Names[i]
,然后free(e);
…
不要忘记记录有关内存使用的约定(谁负责调用malloc
和free
)。 阅读有关C动态内存分配的更多信息(并且害怕内存碎片和缓冲区溢出以及任何其他未定义的行为 )。
如果使用早于GCC 5的GCC,请确保使用gcc -std=c99 -Wall
进行编译,因为旧GCC 4编译器的默认标准是C89。 对于较新的编译器,请询问所有警告以及更多警告,例如gcc -Wall -Wextra
…
TL; DR回答 – 不,你不能。
详细说明,让我引用C11
,章节§6.7.2.1, Structure and union specifiers
( 强调我的 )
结构或联合的成员可以具有除可变修改类型之外的任何完整对象类型。 […]
并且, VLA是可变修改的类型。
但是,引用相同的标准,关于柔性arrays成员
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型; 这称为灵活的arrays成员 。 […]
所以,你可以做点什么
typedef struct { uint8_t No_Of_Employees; uint8_t* Employee_Names[]; }st_employees;
之后,您可以在运行时动态地将内存分配给Employee_Names
(以及Employee_Names[i]
)并使用它。
据我了解,这是不可能的; 根据不同的字段定义一个结构的字段是不可能的。
没有,
定义结构时,必须确认其大小,以便在声明该结构类型的变量时,可以为该变量分配内存。
想想这个场景。 如果要声明st_employees
类型的变量p
,由于尚未设置No_Of_Employees
,因此未确认变量p
的大小,因此无法分配变量的内存。 但是,如果不声明st_employees
类型的变量,则无法设置st_employees
。 这是一个悖论。
您可以使用动态分配执行此操作,如下所示:
#include #include #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
当然这是一个例子,你必须检查分配,精确的sizeof类型和释放内存。
请注意,此方法允许创建可以具有不同类型的对象集合,并且不需要使用任何特定的C编译器版本或选项。
但是,在非常基本的情况下(如在OP示例中),它不是更好的解决方案,因为它会碎片化内存(每个对象一次分配)。 所以谨慎使用它。