C语言 我们可以有一个可变长度数组类型的结构元素吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32311269/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can we have a struct element of type Variable length array?
提问by user12345
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;
回答by Basile Starynkevitch
If coding in C99or 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).
如果在C99或 C11 中编码,您可能想要使用灵活的数组成员(您没有给出明确的维度,但您应该在运行时在头脑中制定一个关于它的约定)。
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).
对于任何阵列,灵活阵列成员的每个插槽都有固定的大小。我正在使用指针(例如,我的 Linux/x86-64 机器上的 8 个字节)。
(In old compilers before the C99 standards, you might try give a 0dimension like char* Employee_Names[0];even if it is against the standard)
(在 C99 标准之前的旧编译器中,即使它违反标准,您也可以尝试给出一个0维度char* Employee_Names[0];)
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
你可能会使用(使用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");
You'll need a void destroy_employee(st_employee*e)function (left as an exercise to the reader). It probably should loop on ito freeevery e->Employee_Names[i], then free(e);...
您将需要一个void destroy_employee(st_employee*e)函数(留给读者作为练习)。它可能应该循环i到freeeach e->Employee_Names[i],然后free(e);......
Don't forget to document the conventions about memory usage (who is in charge of calling mallocand free). Read more about C dynamic memory allocation(and be scared of memory fragmentationand buffer overflowsand any other undefined behavior).
不要忘记记录有关内存使用的约定(谁负责调用malloc和free)。阅读有关C 动态内存分配的更多信息(并害怕内存碎片和缓冲区溢出以及任何其他未定义的行为)。
If using a GCColder than GCC 5be sure to compile with gcc -std=c99 -Wallsince 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...
如果使用GCC年纪比GCC 5一定要与编制gcc -std=c99 -Wall,因为旧GCC编译器4的默认标准是C89。对于较新的编译器,要求所有警告和更多警告,例如gcc -Wall -Wextra...
回答by Sourav Ghosh
TL;DRanswer - No, you cannot.
TL;DR回答 - 不,你不能。
To elaborate, let me quote C11, chapter §6.7.2.1, Structure and union specifiers(emphasis mine)
为了详细说明,让我引用C11第 6.7.2.1 章,Structure and union specifiers(强调我的)
A member of a structure or union may have any complete object type other than a variably modified type.[...]
结构或联合的成员可以具有除可变修改类型之外的任何完整对象类型。[...]
and, a VLAis a variably modified type.
并且,VLA是可变修改的类型。
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.
之后,您可以在运行时动态地为Employee_Names(和Employee_Names[i])分配内存并使用它。
回答by Codor
To my understanding, this is not possible; it is impossible to have one field of a struct defined in terms of a different field.
据我了解,这是不可能的;不可能根据不同的字段定义结构的一个字段。
回答by Haris
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 pof the type st_employees, since the No_Of_Employeesis not set yet, the size of the variable pis not confirmed, hence memory for the variable cannot be allocated. But you cannot set No_Of_Employeeswithout declaring a variable of type st_employees. Its a paradox.
想想这个场景。当你想声明一个p类型的变量时st_employees,由于No_Of_Employees还没有设置,变量的大小p没有确定,因此不能为变量分配内存。但是您不能在No_Of_Employees不声明 type 变量的情况下进行设置st_employees。它是一个悖论。
回答by daouzli
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.
请注意,此方法允许创建可以具有不同类型的对象集合,并且无需使用任何特定的 C 编译器版本或选项。
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.
然而,在非常基本的情况下(如在 OP 示例中),它不是更好的解决方案,因为它会分割内存(每个对象一个分配)。所以请谨慎使用。

