如何增加指向具有可变长度数组的结构的指针?

How do I increment the pointer to a structure which has variable length array?

我在访问指向具有可变大小数组的结构(传递给函数的数组)的指针时遇到问题。

        char name[20];
        char value[20];
   }param_t;
   typedef struct object {
        char name[20];
        int no_of_params;
        param_t params[];
   };

int main()
{
    int no_of_objs = 3, no_of_params = 5;
    object_t *objs = malloc(no_of_objs * (sizeof(object_t) + (no_of_params * sizeof(param_t)) );
     //...
     //...

     objs++;  //Increment to point to the next item <-- Problem: ignores params[] size

     // blah
     // blah
     // blah

我已经分配内存有 3 个 object_t,每个 object_t 存储 5 个 param_t。

内存分配很好,我可以为成员设置值。 objs[0] 非常好。 现在,如果我增加 objs (objs++) 以指向下一个对象,它实际上指向前一个对象的参数地址。它完全忽略了 params[]。 现在,如果我为第二个 *objs 设置值,它实际上会覆盖前一个 *objs.

的 params[]

我的问题是:这是 C 编译器中的错误吗? 如果没有,如何遍历objs?

这不是 C 编译器中的错误,只是使用可变长度数组的缺点。

允许编译器将 struct 的可变长度数组成员视为对 sizeof 没有贡献。

这有效地破坏了指针算法,这意味着您不能像您所说的那样轻松 "traverse the objects"。

恐怕这就是生活。从 C11 中删除可变长度数组作为强制要求的充分理由。

根据 Bathsheba 的回答,您最好将其实现为指向对象的指针数组:

int no_of_objs = 3, no_of_params = 5;
object_t **objs = malloc(no_of_objs * sizeof(object_t *);
for (int i=0; i<no_of_objs; i++)
    objs[i]= malloc ((sizeof(object_t) + (no_of_params * sizeof(param_t)) );

如果您确实需要将此内存分配为单个块,则需要确定适当对齐的元素大小:

size_t object_t_size(size_t nparams)
{
    return (offsetof(object_t, params[nparams]) | (_Alignof(object_t) - 1)) + 1;
}

这里,nparams是分配给object_tparams个灵活数组成员的param_t个元素数。

为了向前遍历包含具有 params 个灵活数组成员的 object_t 集合的内存块,您需要一种方法来找到下一个 object_t 的位置:

object_t *next_object_t(object_t *obj, size_t nparams)
{
    return (object_t *)((char *)obj + object_t_size(nparams));
}

即使 object_t 具有不同的大小(包括它们的 params 灵活数组成员)也可以使用以上方法,只要知道每个个体 object_t 的大小并且分配后不会改变(或者至少,在没有代码重新分配内存和随机播放内容以扩展或减小特定 object_t 的大小时)。

如果集合中的所有object_t大小相同(包括其params灵活数组成员的固定大小),则可以获得指向的指针第i个元素:

object_t *indexed_object_t(object_t *base, size_t nparams, size_t idx)
{
    return (object_t *)((char *)base + object_t_size(nparams) * idx);
}

请注意,上述函数不适用于从任意元素向后索引。这可以通过为索引使用带符号类型并将 object_t_size 的 return 值转换为适当宽的带符号整数类型来解决:

object_t *indexed_object_t(object_t *base, size_t nparams, int idx)
{
    return (object_t *)((char *)base + (intmax_t)object_t_size(nparams) * idx);
}