Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何创建已知最大大小的结构的结构_C_Memory Management_Struct_Arm_Cmsis - Fatal编程技术网

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

C 如何创建已知最大大小的结构的结构,c,memory-management,struct,arm,cmsis,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 matr

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

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

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;
作为参考,此矩阵定义和稍后使用的初始化函数来自中的
arm\u math

我很难理解如何创建
数据集
变量。根据本文的回答和讨论,我明白我不能神奇地期望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;
}
基本上,我从一个假设开始,即矩阵的数量和它们包含的元素的最大数量都是已知的,因此保留了足够的内存

我有以下问题:

  • 对于这种嵌套结构,整体方法是否正确
  • 数据集
    结构的空间分配是否正确
  • 我是否确实确保我创建的
    dataset
    结构中包含的所有
    arm\u matrix\u instance\u f32
    元素都有足够的空间容纳它们的所有元素
  • 我声明该结构包含
    A、B、C
    。如果我以另一个顺序初始化它们会发生什么?例如,如果
    B
    仍未声明,结构如何知道
    A
    C
    之间要保留多少空间

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

    这里,
    arm\u matrix\u instance\u f32
    不包含数组,只包含一个指针。而
    数据集
    包含其中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;
    }
    

    我认为您应该对此采取更细粒度的方法,并从分别为每个
    arm\u matrix\u实例\u f32
    分配空间开始。考虑为这些实例创建工厂函数。它将生成更可读的代码,并允许您简单地用其他实例替换
    数据集中的
    arm\u matrix\u instance\u f32

    另一方面,如果您始终知道矩阵的数量及其包含的元素的最大数量,则可以使用复合文字来生成数据集:

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

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

    要创建类型为
    dataset
    (或任何
    struct
    )的变量,请执行以下操作:

    就这样。没别的了

    要在堆上分配类型为
    dataset
    (或任何
    struct
    )的对象,请执行以下操作:

    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 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 free_dataset(dataset* dp) {
           destroy_matrix(&dp->A);
           destroy_matrix(&dp->B);
           destroy_matrix(&dp->C);
           free(dp);
    }
    
    关于矩阵初始化。有一个库函数可以执行此操作,但它需要一个指向其数据数组的指针,该指针应该分配到某个位置。我猜它就住在堆上

    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 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
    函数。

    memset(d,0,sizeof(*d))不会将数据归零。使用
    calloc
    查看这里的
    arm\u mat\u init\u f32
    函数定义:我想知道像
    arm\u mat\u release\u f32
    这样的函数在哪里?如果这样的函数不存在,我可以猜测,
    arm\u mat\u init\u f32
    只填充
    arm\u matrix\u instance\u f32
    字段,不进行任何分配。在这种情况下,您的代码是错误的,因为
    create\u dataset
    函数退出后,所有
    pData
    指针都将无效。但是,您需要知道您正在使用的API,请提供更多信息以获得答案。
    struct
    中没有数组。指针不是数组。这似乎是一些裸机MCU系统。在这样的系统上使用
    malloc
    &co通常是一个非常糟糕的主意。无论如何,这是一个XY问题。你用了一个非常错误的方法。谢谢你的澄清。这让我知道我应该把手放在哪里。知道为什么答案被否决了吗?也许有更优雅的方式来运行初始化函数,而不是硬编码大小?@raggot:
    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
    }