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");