使用C的另一个struct内部的灵活长度struct数组

时间:2010-03-12 02:30:21

标签: c arrays struct

您好我正在尝试使用C来实现一个简单的结构:
2盒,每盒含有不同数量的颗粒;确切的粒子数在main()中传递。

我写了以下代码:

typedef struct Particle{
    float x;
    float y;
    float vx;
    float vy;
}Particle;

typedef struct Box{
    Particle p[];
}Box;

void make_box(Box *box, int number_of_particles);

int main(){
    Box b1, b2;
    make_box(&b1, 5);  //create a box containing 5 particles
    make_box(&b2, 10); //create a box containing 10 particles
}

我尝试使用以下代码实现make_box

void make_box(struct Box *box, int no_of_particles){
    Particle po[no_of_particles];
    po[0].x = 1;
    po[1].x = 2;
    //so on and so forth...
    box->p = po;
}

它总是给我“无效使用灵活的阵列成员”。非常感谢,如果有人能够对此有所了解。

6 个答案:

答案 0 :(得分:2)

void make_box(struct Box *box, int no_of_particles){
    Particle po[no_of_particles];
    //...
    box->p = po;
}

po是一个局部变量,它的存储空间自动分配在堆栈上;返回它的地址是一个坏主意。你应该从堆中分配内存,并记住在完成这些框后释放内存:

#include <stdlib.h>
#include <stdio.h>

typedef struct Particle_ {
    float x;
    float y;
    float vx;
    float vy;
} Particle;

typedef struct Box_ {
    Particle *p;
} Box;

void make_box(Box *box, int no_of_particles);

void make_box(Box *box, int no_of_particles){
    Particle *po = (Particle *) malloc ( no_of_particles*sizeof(Particle) );
    po[0].x = 1;
    po[1].y = 2;
    //so on and so forth...
    box->p = po;
}

void destroy_box(Box *box){
    free(box->p);
}


int main(){
    Box b1, b2;
    make_box(&b1, 5);  //create a box containing 5 particles
    make_box(&b2, 10); //create a box containing 10 particles

    // do the job...
    printf("box b1, point 0, x: %5.2f\n", b1.p[0].x);
    printf("box b2, point 1, y: %5.2f\n", b2.p[1].y);

    destroy_box(&b1);
    destroy_box(&b2);

    return 0;
}

答案 1 :(得分:1)

您无法分配到Particle p[],只需使用Particle* p

当然,您需要在堆上分配粒子数组,而不是堆栈!否则,只要您离开函数make_box,它就会被销毁。

void make_box(struct Box *box, int no_of_particles){
    Particle* po = (Particle*)malloc(sizeof(Particle)*no_of_particles);
    for (int i = 0; i < no_of_particles; i++)
        po[0].x = i;
    //so on and so forth...
    box->p = po;
}

struct Box
{
    Particle* p;
};

不要忘记在不再需要时释放内存。

答案 2 :(得分:1)

您需要动态分配struct Box

struct Box *box1 = malloc(sizeof *box1 +
                          sizeof (Particle[number_of_particles]));

for (size_t i=0; i < number_of_particles; ++i)
    box1->p[i] = po[i];
/* or memcpy(box1->p, po, sizeof po); */

但是如果你正在做上述事情,你也可以声明struct Box中有一个指针。如果您希望struct中的所有数据都是连续的,则灵活的数组成员“技巧”非常有用。如果Point *中有struct指针并动态分配,则struct的内存布局和点将不连续。

您收到错误的原因是您无法在C中分配数组,而box->p是一个数组(来自n1124 6.7.2.1p16):

  

但是,当.(或->)运算符的左操作数(指向)具有灵活数组成员且右操作数命名该成员的结构时,其行为如下如果该成员被替换为最长的数组(具有相同的元素类型),该数组不会使结构大于被访问的对象;数组的偏移量应保持为灵活数组成员的偏移量,即使这与替换数组的偏移量不同。如果此数组没有元素,则其行为就好像它有一个元素,但如果尝试访问该元素或生成一个超过它的指针,则行为是未定义的。

除了灵活的阵列成员之外,您还需要在struct中至少有一个其他成员。

答案 3 :(得分:1)

如果你有一个具有灵活数组成员的结构,那么就不能直接创建该类型的对象,因为编译器不知道你想要多长时间。这就是你尝试用这条线做的事情:

Box b1, b2;

这样的struct总是需要动态分配,这意味着你只需要声明指向它们的指针。因此,您可以将该声明更改为:

Box *b1, *b2;

...并更改您的make_box()函数以返回这样的指针:

Box *make_box(int no_of_particles)
{
    Box *box = malloc(sizeof *box + no_of_particles * sizeof box->p[0]);

    if (box)
    {
        box->p[0].x = 1;
        box->p[1].x = 2;
        //so on and so forth...
    }

    return box;
}

void destroy_box(Box *box){
    free(box);
}

int main()
{
    Box *b1 = make_box(5);  //create a box containing 5 particles
    Box *b2 = make_box(10); //create a box containing 10 particles

    // Test that b1 and b2 are not NULL, then do the job...

    destroy_box(b1);
    destroy_box(b2);

    return 0;
}

<强> PS: 您还需要向Box结构添加至少一个其他成员(no_of_particles似乎是一个不错的选择),因为灵活的数组成员不能是结构的唯一成员。

答案 4 :(得分:0)

在Box结构中,为什么不使用指向粒子的指针,以便创建动态数组?

答案 5 :(得分:0)

如果您要使用“灵活数组”,它必须是结构中的最后一个元素。这只是因为编译器无法预测下一个元素的偏移量。此外,在分配结构时,您需要为数组元素分配EXTRA内存。

历史记录: 我过去常常看到的一件事就是这样的做法......

struct a {
  int x, y, z;
  char name[1];
};

struct a *  ptr;

ptr = (struct a*) malloc (sizeof (a) + EXTRA SPACE FOR name);

or

ptr = (struct a*) buffer;   /* <buffer> would have been a passed character array */

以上将允许人们访问超出[name]的界限。完全合法且有效的C,但有潜在的危险,因为你将故意超越最初声明的[name]界限。

小心那里。