c - 如何创建已知最大大小的结构结构

标签 c memory-management struct arm cmsis

<分区>

编辑:我现在意识到我在数组和指针之间造成的混淆。我很欣赏这些评论,但不会使问题更准确,因为它会失去我写它的部分原因。

我正在尝试初始化一个由结构组成的结构,每个结构都包含一个数组。更清楚地说,我有这个矩阵结构:

typedef struct
{
    uint16_t numRows;     /**< number of rows of the matrix.     */
    uint16_t numCols;     /**< number of columns of the matrix.  */
    float32_t *pData;     /**< points to the data of the matrix. */
} arm_matrix_instance_f32;

我需要将这些矩阵对象中的一些组合成一个更大的结构

typedef struct
{
    arm_matrix_instance_f32 A;
    arm_matrix_instance_f32 B;
    arm_matrix_instance_f32 C;
} dataset;

作为引用,这个矩阵定义和后面用到的初始化函数,来自CMSIS中的arm_math库。 .

我很难理解应该如何创建 dataset 变量。按照此 question page 中的答案和讨论,我知道我不能神奇地期望 C 知道要用 dataset d 之类的声明分配多少内存。

仅根据链接问题的解决方案,我想出了一个函数来为 dataset 初始化足够的空间,并使用一个函数来创建 dataset 类型的变量>。我现在有这样的东西:

dataset* create_dataset( void ) {

    uint8_t n_matrices = 3;
    uint8_t n_elements = 9;
    dataset* d= malloc( n_matrices * (sizeof(float32_t)*n_elements + sizeof(uint16_t)*2));
    memset(d, 0, sizeof(*d));

    const float32_t zeros33_f32[9] =
    {
        0.0, 0.0, 0.0,
        0.0, 0.0, 0.0,
        0.0, 0.0, 0.0,
    };
    const float32_t zeros31_f32[3] =
    {
        0.0,
        0.0,
        0.0,
    };
    const float32_t zeros13_f32[3] =
    {
        0.0, 0.0, 0.0,
    };

    arm_mat_init_f32( &(d->A), 3, 3, (float32_t *)zeros33_f32);
    arm_mat_init_f32( &(d->B), 3, 1, (float32_t *)zeros31_f32);
    arm_mat_init_f32( &(d->C), 1, 3, (float32_t *)zeros13_f32);

    return d;
}

基本上我从假设矩阵的数量和它们包含的最大元素数量都是已知的开始,因此预留足够的内存。

我有以下问题:

  1. 整体方法是否适用于此类嵌套结构?
  2. dataset 结构的空间分配是否正确?
  3. 我是否真的确保我创建的 dataset 结构中包含的所有 arm_matrix_instance_f32 元素都有足够的空间容纳所有元素?
  4. 我将该结构声明为包含A、B、C。如果我以另一个顺序初始化它们会怎样?例如,如果 B 仍未声明,结构如何知道在 AC 之间留出多少空间?

最佳答案

要创建类型为 dataset 的变量(或任何类型的 struct):

dataset d;

就是这样。仅此而已。

在堆上分配类型为dataset(或任何struct)的对象:

dataset* dp = malloc(sizeof(dataset));

就是这样。仅此而已。

现在初始化这样的对象是另一回事了。但是为了初始化一些东西,你需要先创建那个东西。最好将创建和初始化这两个过程在思想上分开。

所以你手上有一个未初始化的struct。如何初始化它?逐个字段。

每个字段都是一个矩阵,可能需要自己进行复杂的初始化,因此最好编写一个专门的矩阵初始化函数。先用一个吧,以后再写。假设您必须在堆上分配数据集。

dataset* allocate_dataset() {
       dataset* dp = malloc(sizeof(dataset));
       if (dp == NULL) { /* report out-of-memory error */ }
       init_matrix(&dp->A, 3, 3);
       init_matrix(&dp->B, 3, 1);
       init_matrix(&dp->C, 1, 3);
       return dp;
}

在堆上分配的任何东西最终都必须被释放,所以我们写了一个对称的释放函数:

void free_dataset(dataset* dp) {
       destroy_matrix(&dp->A);
       destroy_matrix(&dp->B);
       destroy_matrix(&dp->C);
       free(dp);
}

关于矩阵初始化。有一个库函数可以执行此操作,但它需要一个指向其数据数组的指针,该指针应分配在某处。我假设它存在于堆中。

void init_matrix(arm_mat_init_f32* mp, int rows, int cols) {
    float32_t* data = malloc(sizeof(float32_t * rows * cols);
    if (data == NULL) { /* report out-of-memory error */ }
    arm_mat_init_f32(mp, rows, cols, data);   
}

销毁矩阵几乎是微不足道的:

void destroy_matrix(arm_mat_init_f32* mp) {
    free (mp->pData);
}

同样,这假定您需要在堆上分配矩阵数据。不一定如此。也许您使用的是内存有限的嵌入式设备。现在让我们假设相反的情况:没有堆。你不需要分配你的数据集,但你仍然需要初始化它:

void init_dataset (dataset* dp);

现在 init_matrix 除了调用 arm_mat_init_f32 什么都不做,所以我们可以直接使用后者:

void init_dataset (dataset* dp) {
    arm_mat_init_f32(&dp->A, 3, 3, (float32_t[]){0,0,0, 0,0,0, 0,0,0});
    arm_mat_init_f32(&dp->B, 3, 1, (float32_t[]){0,0,0});
    arm_mat_init_f32(&dp->C, 1, 3, (float32_t[]){0,0,0});
}

不需要销毁,但您可能仍希望保留不执行任何操作的销毁函数,以防万一,并在适当的时候调用它们。

void destroy_dataset(dataset* dp) { 
    destroy_matrix(&dp->A);
    destroy_matrix(&dp->B);
    destroy_matrix(&dp->C);
}

void destroy_matrix(arm_mat_init_f32* mp) { 
  (void)mp; // suppress compiler warning
}

为什么?因为一旦您改变主意(或切换到不同的设备)并决定在堆上分配矩阵,您不想重做所有 代码。您只需修改 initdestroy 函数即可。

关于c - 如何创建已知最大大小的结构结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51397878/

相关文章:

c - 抑制或拦截来自其他 dll 的 CRT 实例的 CRT 检查

performance - 如何在 Haskell 中获得 5GB 堆的控制权?

c++ - 在 C++ 中追加结构数组

c - GCC 的 __attribute__((__packed__)) 是否保留原始顺序?

c - 为什么我的 yacc 规则不能在这里减少?

c++ - c\c++中线程和并发中一本好的编程书籍推荐

memory-management - Swift 协议(protocol)对象的 ARC

memory-management - 转换内核地址时 pgd_bad、pmd_bad、pud_bad 的含义是什么?

C:为什么 print 语句改变了我的结构成员的值?

c - 如何在 c 中像领结形状一样排列数字