我们可以声明一个可变长度的结构元素吗?
条件如下:
typedef struct
{
uint8_t No_Of_Employees;
uint8_t Employee_Names[No_Of_Employees][15];
}st_employees;
答案 0 :(得分:12)
如果在C99或C11中进行编码,您可能希望使用flexible array members(您没有给出明确的维度,但是您应该在运行时对其进行约定)。< / p>
typedef struct {
unsigned No_Of_Employees;
char* Employee_Names[]; // conventionally with No_of_Employees slots
}st_employees;
对于任何阵列,柔性阵列成员的每个槽都具有固定的大小。我正在使用指针(例如我的Linux / x86-64机器上的8个字节)。
(在C99标准之前的旧编译器中,您可以尝试提供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; i<n; i++) s->Employe_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 dynamic memory allocation(并且害怕memory fragmentation和buffer overflows以及其他任何undefined behavior。)
如果使用早于GCC的GCC 5,请务必使用gcc -std=c99 -Wall
进行编译,因为旧GCC 4编译器的默认标准是C89。对于较新的编译器,请询问所有警告以及更多警告,例如: gcc -Wall -Wextra
...
答案 1 :(得分:5)
TL; DR 回答 - 不,你不能。
详细说明,让我引用C11
,章节§6.7.2.1,Structure and union specifiers
(强调我的)
结构或联合的成员可以具有除a之外的任何完整对象类型 可变修改类型。 [...]
并且,VLA是一种可变的修改类型。
但是,引用同一标准,关于flexible array member
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可以 有一个不完整的数组类型;这称为灵活数组成员。 [...]
所以,你可以做类似
的事情typedef struct
{
uint8_t No_Of_Employees;
uint8_t* Employee_Names[];
}st_employees;
以后,您可以在运行时动态地将内存分配到Employee_Names
(以及Employee_Names[i]
)并使用它。
答案 2 :(得分:1)
据我了解,这是不可能的;根据不同的字段定义结构的一个字段是不可能的。
答案 3 :(得分:1)
NO,
定义结构时,必须确认其大小,以便在声明该结构类型的变量时,可以为该变量分配内存。
想想这个场景。如果要声明p
类型的变量st_employees
,由于尚未设置No_Of_Employees
,因此未确认变量p
的大小,因此变量无法分配。但是,如果不声明No_Of_Employees
类型的变量,则无法设置st_employees
。这是一个悖论。
答案 4 :(得分:0)
您可以使用动态分配执行此操作,如下所示:
#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;
}
当然这是一个例子,你必须检查分配,精确的sizeof类型和释放内存。
请注意,此方法允许创建可以具有不同类型的对象集合,并且不需要使用任何特定的C编译器版本或选项。
然而,在非常基本的情况下(如在OP示例中),它不是更好的解决方案,因为它会碎片化内存(每个对象一次分配)。所以请谨慎使用。