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

将二维数组指定为void*

c
  •  -2
  • Danijel  · 技术社区  · 7 年前

    我正在把一大块内存传递给我的子程序。在子程序中,我将这个内存的一部分分配给内部的1D数组指针。

    typedef struct
    {
        // float a[SIZE_A];
        // float b[SIZE_B];
        // float c[SIZE_C1][SIZE_C2];
    
        float* a;
        float* b;
        float c[][SIZE_C2]; // float** c;
    } OBJ;
    
    
    void init( OBJ* obj, void* mem )
    {
        float* mem_p = (float*)mem; 
    
        obj->a = mem_p; 
        mem_p += SIZE_A;
    
        obj->b = mem_p; 
        mem_p += SIZE_B;
    
        obj->c = ? 
    
    }
    

    如何分配第三个成员,即2d数组?

    3 回复  |  直到 7 年前
        1
  •  2
  •   Candy Gumdrop    7 年前

    宣言 float c[][SIZE_C2] 在结构中声明一个数组数组,数组内联存储在结构中。此声明不包含引用存储在其他位置的数组的任何指针。

    如果希望保留当前的结构签名,可以填充 c 如下:

    memcpy(&obj->c, mem_p, SIZE_C1 * SIZE_C2 * sizeof(float));
    

    这将从 mem_p 进入数组的连续数组 C ,之后 C 不引用任何来自 mem 就像情况一样 a b ,但却保留自己的数据副本。

    请记住,您的结构当前保存 C 作为一个“灵活的数组成员”,因为最外面的数组有一个未指定的大小,这意味着您的结构必须通过 malloc 或者类似的,并且必须给它额外的空间来容纳数组元素:

    OBJ *obj = malloc(sizeof *obj + SIZE_C1 * sizeof(float));
    

    如果你只想在 obj 指的是 MEM 不存储单独的副本,因此 C ,您必须更改 C 在你的结构中:

    float (*c)[SIZE_C2];
    

    这表明 C 成为“指向 SIZE_C2 元素(可以是一个连续的数组序列),而不是一个 西泽C2 元素“。

    可以在 init 功能如下:

    obj->c = (float (*)[SIZE_C2]) mem_p;
    

    如果你想进一步分配 float 字段后 C ,您可以继续递增 梅默普 与此类似,如果不将其转换为指向数组的指针,则C中数组的大小只是其元素类型的大小乘以其元素数:

    /* sizeof(float [SIZE_C2]) == SIZE_C2 * sizeof(float) */
    /* mem_p is a `float *` so goes up in steps of `sizeof(float)` */
    mem_p += SIZE_C1 * SIZE_C2;
    

    使用这种方法,元素仍然可以作为 obj->c[1][2] ,就像当前结构的签名一样。

    由于指向数组的指针在c中使用起来有点棘手,并且需要内部数组具有固定的大小,所以您可能会发现存储 C 作为普通单身 float * 指针和地址元素就像二维数组一样,由您自己手动操作,例如:

    float f = obj->c[row * SIZE_C2 + col];
    
        2
  •  0
  •   Goswin von Brederlow    7 年前

    我一直在想这个,也许你把整件事都复杂化了。据我所知,您从静态分配结构开始:

    typedef struct
    {
        float a[SIZE_A];
        float b[SIZE_B];
        float c[SIZE_C1][SIZE_C2];
    } OBJ;
    

    现在你希望内存是动态分配的。所以你要分配一大块大小的内存 sizeof(float) * (SIZE_A + SIZE_B + SIZE_C1 * SIZE_C2) 并在结构中设置指向该内存的指针。

    但是请注意,内存块的大小与原始结构的大小完全相同吗?那么为什么不动态地分配原始结构,而不是将结构的成员更改为指针呢?

    void init( OBJ** obj, void* mem )
    {
        *obj = (Obj*)mem;
        memset(mem, 0, sizeof(OBJ));
    }
    
    void cleanup( OBJ** obj) {
        free(*obj);
        *obj = NULL;
    }
    

    您甚至可以将malloc()移到in it()函数中,使其更易于使用,就像我在cleanup()中有free()调用一样。

        3
  •  -1
  •   Goswin von Brederlow    7 年前

    你不能。在你的结构中 float c[][SIZE_C2]; 是位于结构内部的二维浮点数数组。它不是指向可以指向已分配内存的对象的指针。必须使c成为指向二维数组的指针,如下所示:

    #define SIZE_A 4
    #define SIZE_B 8
    #define SIZE_C1 12
    #define SIZE_C2 16
    
    struct Float2D {
        float c[0][SIZE_C2];
    };
    
    typedef struct
    {
        // float a[SIZE_A];
        // float b[SIZE_B];
        // float c[SIZE_C1][SIZE_C2];
    
        float* a;
        float* b;
        struct Float2D *c;
    } OBJ;
    
    
    void init( OBJ* obj, void* mem )
    {
        float* mem_p = (float*)mem; 
    
        obj->a = mem_p; 
        mem_p += SIZE_A;
    
        obj->b = mem_p; 
        mem_p += SIZE_B;
    
        obj->c = (struct Float2D*)mem_p;
    }
    

    注意:中的0 float c[0][SIZE_C2]; 是必需的,因为不能有只包含flex数组的结构。这可能是gcc编译器的扩展。也许您可以找出如何在不使用额外结构的情况下指定类型。