代码之家  ›  专栏  ›  技术社区  ›  raggot

如何创建已知最大大小结构[关闭]结构

  •  1
  • raggot  · 技术社区  · 6 年前

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

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

    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;
    

    作为参考,此矩阵定义和稍后使用的初始化函数来自 arm_math 图书馆在 CMSIS .

    我很难理解我应该如何创造一个 dataset 变量在回答和讨论之后 question page ,我理解我无法神奇地期望C知道使用如下声明分配多少内存 dataset d 是的。

    在解决了这个链接的问题之后,我设计了一个函数来初始化足够的空间 数据集 ,并使用函数创建类型为 数据集 是的。我现在有这样的东西:

    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. 是为 数据集 结构正确吗?
    3. 我真的能保证 arm_matrix_instance_f32 包含在 数据集 我创建的结构有足够的空间容纳所有元素吗?
    4. 我声明结构包含 A, B, C . 如果我用另一个顺序初始化它们会怎么样例如,结构如何知道在 A C 如果 B 还没有申报?
    3 回复  |  直到 6 年前
        1
  •  1
  •   n. m. could be an AI    6 年前

    创建类型为的变量 dataset (或任何 struct 就这点而言:

    dataset d;
    

    就这样。没别的了。

    分配类型为的对象 数据集 (或任何 结构 就这件事而言)堆在一起:

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

    就这样。没别的了。

    现在到 初始化 这样一个对象是完全不同的问题但是为了初始化一些东西,你需要先创建一些东西最好将这两个过程,创建和初始化,在精神上分开。

    所以你有一个无知的 结构 在你的手上如何初始化?一个接一个。

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

    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
    }
    

    为什么?因为你不想重做 全部的 一旦你改变主意(或切换到另一个设备)并决定在堆上分配矩阵。你只要修改你的 init destroy 功能。

        2
  •  1
  •   pbn    6 年前

    我认为您应该对此采取更细粒度的方法,并从为每个 arm_matrix_instance_f32 另外。考虑为这些实例创建一个工厂函数它将产生更可读的代码,并允许您简单地替换 arm矩阵实例 在你的 dataset 还有其他的例子。

    另一方面,如果您总是知道矩阵的数目和它们包含的元素的最大数量,则可以使用复合文字来生成数据集:

     dataset create()
     {
         return (dataset) {
             .A = {
                 3, 3, (float32_t [])  {
                     1.0, 2.0, 3.0,
                     4.0, 5.0, 6.0,
                     7.0, 8.0, 9.0,
                 }
             },
             .B = {
                 3, 3, (float32_t [])  {
                     2.0, 0.0, 0.0,
                     0.0, 0.0, 0.0,
                     0.0, 0.0, 0.0,
                 }
             },
             .C = {
                 3, 3, (float32_t [])  {
                     2.0, 0.0, 0.0,
                     0.0, 0.0, 0.0,
                     0.0, 0.0, 0.0,
                 }
             },
    
         };
     }
    

    这将使您免于堆分配/释放。

        3
  •  0
  •   Serge Ballesta    6 年前

    注意,指针和数组是不同的动物!

    这里,那个 arm_matrix_instance_f32 不包含数组,但包含指针以及 dataset 包含其中3个。完全停止。

    这意味着这条线是完全错误的:

    dataset* d= malloc( n_matrices * (sizeof(float32_t)*n_elements + sizeof(uint16_t)*2));
    

    相反,您应该分别分配结构和数组:

    dataset* create_dataset( void ) {
    
        dataset* d = malloc(sizeof(*d));                  // allocate memory for the structs
        if (d == NULL) return NULL;                       // could not allocate
        // allocate memory for the arrays (9 + 3 + 3)
        float32_t *array = malloc(15 +  * sizeof(*array));
        if (array == NULL) {
            free(d);                                      // free d if array not allocated
            return NULL;
        }
    
        for (int i=0; i<15; i++) array[i] = 0.;           // zeroes the arrays
    
        arm_mat_init_f32( &(d->A), 3, 3, array);          // pass 9 first elements to A
        arm_mat_init_f32( &(d->B), 3, 1, array + 9);      // pass following 3 to B
        arm_mat_init_f32( &(d->C), 1, 3, array + 12);     // pass last 3 to C
    
        return d;
    }
    

    因为你已经把一切 malloc 稍后您将不得不释放它:

    void destroy_dataset(dataset *d) {
        free(d->A.pData);      // free the array (A got the beginning of the allocated array)
        free(d);               // and the struct
    }