C 我们可以有一个可变长度数组类型的结构元素吗?

C 我们可以有一个可变长度数组类型的结构元素吗?,c,struct,variable-length-array,C,Struct,Variable Length Array,我们可以声明长度可变的结构元素吗 条件如下: typedef struct { uint8_t No_Of_Employees; uint8_t Employee_Names[No_Of_Employees][15]; }st_employees; 据我理解,这是不可能的;不可能用不同的字段定义结构的一个字段。否 定义结构时,必须确认其大小,以便在声明该结构类型的变量时,可以为该变量分配内存 想想这个场景。当您想要声明类型为st_employees的变量p时,由于尚未设置No_of

我们可以声明长度可变的结构元素吗

条件如下:

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

据我理解,这是不可能的;不可能用不同的字段定义结构的一个字段。

定义结构时,必须确认其大小,以便在声明该结构类型的变量时,可以为该变量分配内存


想想这个场景。当您想要声明类型为
st_employees
的变量
p
时,由于尚未设置
No_of_employees
,因此变量
p
的大小未得到确认,因此无法分配变量的内存。但是,如果不声明类型为
st\u Employees
的变量,则无法设置
No\u Of_Employees
。这是一个悖论;DR回答-不,你不能

为了详细说明,让我引用
C11
,第§6.7.2.1章,
结构和联合说明符
(重点)

结构或联合的成员可以具有除 可变修改类型。[…]

并且,a是一种可变修改类型

但是,引用同一标准,关于

作为特例,具有多个命名成员的结构的最后一个元素可以 具有不完整的数组类型;这称为灵活数组成员。[……]

所以,你可以这样做

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

之后,您可以在运行时将内存动态分配给
员工姓名(以及
员工姓名[i]
),并加以利用。

您可以通过动态分配来实现这一点,如下所示:

#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;
}
#包括
#包括
#定义元素15的大小
#定义uint8\u t字符
类型定义结构
{
uint8员工人数;
uint8\u t**员工姓名;
}st_员工;
int main()
{
int i;
st_员工EMP;
emps.No_Of_Employees=2;//元素数
//分配元素的数量
emps.Employee_name=malloc(emps.No_员工);
对于(i=0;i
对于任何数组,灵活数组成员的每个插槽都有固定的大小。我使用的是指针(例如,在我的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;
 }
你需要一个
void destroy\u employee(st\u employee*e)
函数(留给读者作为练习)。它可能应该循环
i
free
每个
e->employee\u名字[i]
,然后
free(e);

不要忘记记录有关内存使用的约定(谁负责调用
malloc
free
)。阅读更多关于(以及害怕和其他)的信息


如果使用较旧的编译器,请务必使用
gcc-std=c99-Wall
进行编译,因为旧的gcc 4编译器的默认标准是C89。对于较新的编译器,请询问所有警告以及更多警告,例如
gcc-Wall-Wextra

编译器会说什么?您可以做的是将数组声明为灵活的数组成员,以后可以在运行时为其分配空间。来自C标准的示例:
struct s{int n;double d[];};int m=/*some value*/;struct s*p=malloc(sizeof(struct s)+sizeof(double[m]));
我正在使用IAR gcc编译器哪个版本的编译器?什么编译命令行?你是用
gcc-std=c99-Wall
编译的吗?@user12345除非我一直生活在岩石下面,否则IAR和gcc是截然不同的编译器。出于好奇,哪一个是目标处理器?不,别这样,绝对没有在堆中分割结构的内存的原因。相反,将
Employee_Names
声明为灵活的数组成员,同时在相邻内存中为结构分配空间+数组大小。来自C标准的示例:
struct s{int n;double d[];};int m=/*some value*/;struct s*p=malloc(sizeof(结构s)+sizeof(双[m]))
我不同意。这是一种灵活的方法。它允许您使用任何类型的数据。在那个特定的示例中,这不是更好的方法,但问题是使用可变结构长度数据,示例显示了一个特定大小的元素。@Lundin不幸的是,您在没有ot的情况下否决了该问题的有效解决方案她的解决方案提出了。我的解决方案应该有效。我猜OP忘记了
-std=c99
标志;而你的解决方案确实是大量分割内存,这在嵌入式软件中是一个问题。@daouzli我投了反对票,因为你鼓吹不好的做法:不必要的堆碎片(伪数组),而不是分配相邻内存中的所有内容(真正的数组)。除了堆碎片,您的方法还会导致您的程序变得不必要的慢,而毫无收获。这不仅是因为行之间存在各种表查找开销指令,更重要的是,相邻的存储单元意味着您的程序可以更好地利用片内数据缓存。我是一个嵌入式程序d程序员。我正在使用IAR编译器,它给出的错误是:表达式必须有一个常量值。我启用了C99标准和VLA。然后你应该将你的编译器升级到C99兼容的编译器。尝试我正在使用C99标准并启用VLA,然后你应该
 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;
 }
 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");