具有不同长度数组成员的结构数组 C
Array of struct with different length array members C
我正在 C99 中实现一些查找数据(作为软件 PLECS 中的 C 脚本)。
我想创建一个结构数组,其中包含一个(稍后将是三个)数组成员,每个结构的长度都不同(但始终已知)。我想在声明结构数组时直接传递数据。
这是我到目前为止尝试过的方法。
#include <stdlib.h>
struct SomeStruct{
double a;
double *b;
};
struct SomeStruct StructArray[3] = {
[0].a = 1,
[0].b = (double*)malloc(2*sizeof(double)),
[0].b = {1.01, 2.01}, //obviously wrong
[1].a = 2,
[1].b = (double*)malloc(3 * sizeof(double)),
[1].b = { 1.01, 2.01, 3.01, }, //obviously wrong
[2].a = 3,
[2].b = (double*)malloc(4 * sizeof(double)),
[2].b = { 1.01, 2.01, 3.01, 4.01 }, //obviously wrong
};
不幸的是,我的 C 有点生疏,我不知道如何取消引用结构中的指针。 *([N].b) 不起作用。
这可能吗?还是有更优雅的灵魂?
PS:数据会很大,struct 数组的长度约为 200,并且每个数组中将有三个最大长度为 400 的数组。此代码是从 MATLAB 脚本作为头文件生成的。
编辑:以上已由@Gilles 解决,以下内容仍然值得关注
这是另一种方法,在运行时初始化。为什么下面的位不起作用?
#include <stdlib.h>
typedef struct {
double a;
double *b;
} SomeStruct;
SomeStruct StructArray[2]; //Sample struct
void initializeLUT() // Filling the Struct with Data
{
StructArray[0].a = 1;
StructArray[0].b = (double*)calloc(2, sizeof(double));
StructArray[0].b = { 1.01, 2.01 }; // does not work
StructArray[1].a = 2;
StructArray[1].b = (double*)calloc(3, sizeof(double));
*(StructArray[1].b) = { 1.01, 2.01, 3.01, }; //does not work either
}
在全局变量中,初始化器必须是常量。以这种方式设计语言的原因是,对于全局数据,初始化程序通常包含嵌入程序二进制文件中的数据,而不是在运行时执行的代码。因此,即使您将对 malloc
的调用和元素值打包到一个函数中,您仍然无法使用它来初始化数据。
如果你想要一个静态初始化器,将指针的初始化与其最初指向的数组的初始化分离。使初始数组成为全局变量,这是您为它们指定初始值设定项的唯一方法。
double row1[] = { 1.01, 2.01 };
double row2[] = { 1.01, 2.01, 3.01 };
double row3[] = { 1.01, 2.01, 3.01, 4.01 };
struct SomeStruct StructArray[3] = {
[0].a = 1,
[0].b = row1,
[1].a = 2,
[1].b = row2,
[2].a = 3,
[2].b = row3,
};
如果你想使用 malloc
因为你想在运行时释放数组或调整数组大小,那么将指针初始化为 NULL
,然后从你自己的初始化代码中调用 malloc
(例如,在 main
中,或者更好,在同一文件 my_module.c
中定义的函数 init_my_module
中调用 malloc
,其中定义了 StructArray
,并调用 init_my_module
来自 main
)。您可能仍然需要为初始数组内容设置全局变量。
请注意,如果数组具有固定大小,更好的方法是让 SomeStruct
直接包含数组,而不是指针。但是这种方法不适用于不同大小的数组:你可以有一个带有 flexible array member 的结构,但是你不能把那个结构放在一个数组中,因为数组元素需要有一个恒定的大小。
另请注意,您可能应该将数组大小存储在某处(通常在结构的字段中)。
由于数据显然是动态的,您需要在 运行 时间内对其进行初始化。我认为您正在寻找另一个名为 "flexible array member" 的 C99 功能,而不是使用指定的初始值设定项,它允许结构以安全的方式在末尾具有可变大小的结构。示例:
#include <stdlib.h>
#include <string.h>
typedef struct
{
double a; // whatever this is supposed to be
size_t size;
double data[]; // flexible array member
} SomeStruct;
SomeStruct* SomeStruct_alloc (double a, size_t size, double data[size])
{
SomeStruct* ss = malloc(sizeof(SomeStruct) + sizeof(double[size]));
if(ss == NULL)
{
return NULL;
}
ss->a = a;
ss->size = size;
memcpy(ss->data, data, sizeof(double[size]));
return ss;
}
int main()
{
SomeStruct* arr[3];
arr[0] = SomeStruct_alloc(1, 2, (double[2]){1.01, 2.01});
arr[1] = SomeStruct_alloc(2, 3, (double[3]){1.01, 2.01, 3.01});
arr[2] = SomeStruct_alloc(3, 4, (double[4]){1.01, 2.01, 3.01, 4.01});
return 0;
}
替换
StructArray[0].b = (double*)calloc(2, sizeof(double));
StructArray[0].b = { 1.01, 2.01 }; // does not work
和
{
double* p = calloc(2, sizeof(double));
if (!p) { perror("calloc"); exit(EXIT_FAILURE); };
static const double arr[] = { 1.01, 2.01 };
memcpy (p, arr, 2*sizeof(double));
StructArray[0].b = p;
}
您甚至可以定义一个宏来帮助您,也许:
#define FILLME(Ix,...) do { \
static const double arr[] = {__VA_ARGS__}; \
double*p = calloc(sizeof(arr)/sizeof(double), \
sizeof(double)); \
if (!p) \
{ perror("calloc"); exit(EXIT_FAILURE); }; \
memcpy (p, arr, sizeof(arr)); \
StructArray[ix].b = p; \
} while(0)
然后将其用作
FILLME(0, 1.01,2.01);
顺便说一句,你最好使用 flexible array members(总是在他们的 struct
中)
我正在 C99 中实现一些查找数据(作为软件 PLECS 中的 C 脚本)。
我想创建一个结构数组,其中包含一个(稍后将是三个)数组成员,每个结构的长度都不同(但始终已知)。我想在声明结构数组时直接传递数据。
这是我到目前为止尝试过的方法。
#include <stdlib.h>
struct SomeStruct{
double a;
double *b;
};
struct SomeStruct StructArray[3] = {
[0].a = 1,
[0].b = (double*)malloc(2*sizeof(double)),
[0].b = {1.01, 2.01}, //obviously wrong
[1].a = 2,
[1].b = (double*)malloc(3 * sizeof(double)),
[1].b = { 1.01, 2.01, 3.01, }, //obviously wrong
[2].a = 3,
[2].b = (double*)malloc(4 * sizeof(double)),
[2].b = { 1.01, 2.01, 3.01, 4.01 }, //obviously wrong
};
不幸的是,我的 C 有点生疏,我不知道如何取消引用结构中的指针。 *([N].b) 不起作用。
这可能吗?还是有更优雅的灵魂?
PS:数据会很大,struct 数组的长度约为 200,并且每个数组中将有三个最大长度为 400 的数组。此代码是从 MATLAB 脚本作为头文件生成的。
编辑:以上已由@Gilles 解决,以下内容仍然值得关注
这是另一种方法,在运行时初始化。为什么下面的位不起作用?
#include <stdlib.h>
typedef struct {
double a;
double *b;
} SomeStruct;
SomeStruct StructArray[2]; //Sample struct
void initializeLUT() // Filling the Struct with Data
{
StructArray[0].a = 1;
StructArray[0].b = (double*)calloc(2, sizeof(double));
StructArray[0].b = { 1.01, 2.01 }; // does not work
StructArray[1].a = 2;
StructArray[1].b = (double*)calloc(3, sizeof(double));
*(StructArray[1].b) = { 1.01, 2.01, 3.01, }; //does not work either
}
在全局变量中,初始化器必须是常量。以这种方式设计语言的原因是,对于全局数据,初始化程序通常包含嵌入程序二进制文件中的数据,而不是在运行时执行的代码。因此,即使您将对 malloc
的调用和元素值打包到一个函数中,您仍然无法使用它来初始化数据。
如果你想要一个静态初始化器,将指针的初始化与其最初指向的数组的初始化分离。使初始数组成为全局变量,这是您为它们指定初始值设定项的唯一方法。
double row1[] = { 1.01, 2.01 };
double row2[] = { 1.01, 2.01, 3.01 };
double row3[] = { 1.01, 2.01, 3.01, 4.01 };
struct SomeStruct StructArray[3] = {
[0].a = 1,
[0].b = row1,
[1].a = 2,
[1].b = row2,
[2].a = 3,
[2].b = row3,
};
如果你想使用 malloc
因为你想在运行时释放数组或调整数组大小,那么将指针初始化为 NULL
,然后从你自己的初始化代码中调用 malloc
(例如,在 main
中,或者更好,在同一文件 my_module.c
中定义的函数 init_my_module
中调用 malloc
,其中定义了 StructArray
,并调用 init_my_module
来自 main
)。您可能仍然需要为初始数组内容设置全局变量。
请注意,如果数组具有固定大小,更好的方法是让 SomeStruct
直接包含数组,而不是指针。但是这种方法不适用于不同大小的数组:你可以有一个带有 flexible array member 的结构,但是你不能把那个结构放在一个数组中,因为数组元素需要有一个恒定的大小。
另请注意,您可能应该将数组大小存储在某处(通常在结构的字段中)。
由于数据显然是动态的,您需要在 运行 时间内对其进行初始化。我认为您正在寻找另一个名为 "flexible array member" 的 C99 功能,而不是使用指定的初始值设定项,它允许结构以安全的方式在末尾具有可变大小的结构。示例:
#include <stdlib.h>
#include <string.h>
typedef struct
{
double a; // whatever this is supposed to be
size_t size;
double data[]; // flexible array member
} SomeStruct;
SomeStruct* SomeStruct_alloc (double a, size_t size, double data[size])
{
SomeStruct* ss = malloc(sizeof(SomeStruct) + sizeof(double[size]));
if(ss == NULL)
{
return NULL;
}
ss->a = a;
ss->size = size;
memcpy(ss->data, data, sizeof(double[size]));
return ss;
}
int main()
{
SomeStruct* arr[3];
arr[0] = SomeStruct_alloc(1, 2, (double[2]){1.01, 2.01});
arr[1] = SomeStruct_alloc(2, 3, (double[3]){1.01, 2.01, 3.01});
arr[2] = SomeStruct_alloc(3, 4, (double[4]){1.01, 2.01, 3.01, 4.01});
return 0;
}
替换
StructArray[0].b = (double*)calloc(2, sizeof(double));
StructArray[0].b = { 1.01, 2.01 }; // does not work
和
{
double* p = calloc(2, sizeof(double));
if (!p) { perror("calloc"); exit(EXIT_FAILURE); };
static const double arr[] = { 1.01, 2.01 };
memcpy (p, arr, 2*sizeof(double));
StructArray[0].b = p;
}
您甚至可以定义一个宏来帮助您,也许:
#define FILLME(Ix,...) do { \
static const double arr[] = {__VA_ARGS__}; \
double*p = calloc(sizeof(arr)/sizeof(double), \
sizeof(double)); \
if (!p) \
{ perror("calloc"); exit(EXIT_FAILURE); }; \
memcpy (p, arr, sizeof(arr)); \
StructArray[ix].b = p; \
} while(0)
然后将其用作
FILLME(0, 1.01,2.01);
顺便说一句,你最好使用 flexible array members(总是在他们的 struct
中)