具有不同长度数组成员的结构数组 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 中)