简体   繁体   English

具有不同长度数组成员C的结构数组

[英]Array of struct with different length array members C

I am implementing some lookup data in C99 (as a C-Script in the Software PLECS). 我正在C99中实现一些查找数据(作为PLECS软件中的C脚本)。

I want to create an array of struct with one (later this will be three) array members that will have a different (but always known) length for each struct. 我想用一个(以后将是三个)数组成员创建一个结构数组,每个结构的长度都不同(但始终是已知的)。 I would like to pass the data directly as I declare the struct array. 我想在声明struct数组时直接传递数据。

Here is what I tried so far. 这是我到目前为止尝试过的。

#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
};

Unfortunately my C is a little rusty and I cant figure out how to dereference the pointer inside the struct. 不幸的是,我的C有点生锈,我无法弄清楚如何取消引用结构中的指针。 *([N].b) does not work. *([N] .b)不起作用。

Is this even possible? 这有可能吗? Or is there maybe a more elegant soultion? 还是有更优雅的灵魂?

PS: The Data will be quite large, the struct array will have a length of about 200 and there will three arrays of up to length 400 in each of them. PS:数据将非常大,结构数组的长度约为200,并且每个数组中将包含三个长度最大为400的数组。 The code for this is generated as a header file from a MATLAB Script. 为此的代码从MATLAB脚本生成为头文件。

EDIT: Above has been solved by @Gilles, the following is still of interest 编辑:上面已经由@Gilles解决了,下面仍然很有趣

Here the alternative way, initializing at runtime. 这里是替代方法,在运行时初始化。 Why does the following bit not work? 为什么以下位不起作用?

#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
}

In a global variable, the initializer must be a constant. 在全局变量中,初始化器必须是一个常量。 The reason the language is designed that way is that for global data, the initializer typically consists of data embedded in the program binary, rather than code that is executed at runtime. 之所以设计这种语言,是因为对于全局数据,初始化程序通常由嵌入在程序二进制文件中的数据组成,而不是在运行时执行的代码组成。 As a consequence, even if you packaged the call to malloc and the element values into a function, you still wouldn't be able to use that to initialize your data. 结果,即使将对malloc的调用和元素值打包到一个函数中,您仍然无法使用该函数来初始化数据。

If you want to have a static initializer, decouple the initialization of the pointer from the initialization of the array it initially points to. 如果要使用静态初始化程序,请将指针的初始化与它最初指向的数组的初始化分离。 Make the initial array global variables, that's the only way you'll get to specify an initializer for them. 使初始数组成为全局变量,这是为它们指定初始化程序的唯一方法。

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,
};

If you wanted to use malloc because you wanted to free or resize the arrays at runtime, then initialize the pointers to NULL , and call malloc from your own initialization code (eg in main , or better, call malloc in a function init_my_module defined in the same file my_module.c where StructArray is defined, and call init_my_module from main ). 如果要使用malloc是因为要在运行时释放或调整数组的大小,请初始化指向NULL的指针,然后从您自己的初始化代码中调用malloc (例如,在main或更高版本中,在函数init_my_module定义的malloc中调用定义了StructArray相同文件my_module.c ,并从main调用init_my_module You'll probably still need to have global variables for the initial array contents. 您可能仍需要为初始数组内容使用全局变量。

Note that if the arrays had a fixed size, a better approach would be to make SomeStruct contain the arrays directly, rather than pointer. 请注意,如果数组具有固定大小,则更好的方法是使SomeStruct直接包含数组,而不是指针。 But this approach doesn't work for arrays of varying size: you can have a structure with a flexible array member , but you can't put that structure in an array, because array elements need to have a constant size. 但是这种方法不适用于大小可变的数组:您可以使用带有灵活数组成员的结构,但是不能将这种结构放入数组中,因为数组元素需要具有恒定的大小。

Also note that you should probably store the array size somewhere (typically in a field of the structure). 还要注意,您可能应该将数组大小存储在某个位置(通常存储在结构的字段中)。

Since the data is apparently dynamic, you need to initialize it in run-time. 由于数据显然是动态的,因此您需要在运行时对其进行初始化。 Rather than using designated initializers, I think you are looking for another C99 feature called "flexible array member", which allows a struct to have a variable-sized struct at the end, in a safe manner. 我认为您不是在使用指定的初始化程序,而是在寻找另一种称为“柔性数组成员”的C99功能,该功能允许结构以安全的方式在最后具有可变大小的结构。 Example: 例:

#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;
}

Replace 更换

StructArray[0].b = (double*)calloc(2, sizeof(double));
StructArray[0].b = { 1.01, 2.01 }; // does not work

with

{
  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;
}

you might even define a macro to help you, maybe: 您甚至可以定义一个宏来帮助您,也许:

#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)

then use it as 然后将其用作

FILLME(0, 1.01,2.01);

BTW, you'll probably better use flexible array members (always last in their struct ) 顺便说一句,您可能最好使用灵活的数组成员 (始终位于其struct

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM