动态声明的struct数组

时间:2014-04-08 13:38:10

标签: c

假设我们要构造一个结构数组,其中在编译时无法知道结构的定义。

这是SSCCE

#include <stdlib.h>

int main(int argc, char *argv[]){
    if (argc < 3) return 1;
    int n = atoi(argv[1]);
    int k = atoi(argv[2]);
    if ((n < 1) || (k < 1)) return 2;

    // define struct dynamically
    typedef struct{
        int a[n];
        short b[k];
    }data_point_t;

    int m = 10;
    // construct array of `m` elements
    data_point_t *p = malloc(sizeof(data_point_t)*m);

    // do something with the array
    for(int i = 0; i < m; ++i) p[i].a[0] = p[i].b[0] = i; 
    free(p);
    return 0;
}

这适用于gccC99),但它不适用于clang,这会产生:

error: fields must have a constant size: 
       'variable length array in structure' extension will never be supported

所以我显然依赖于gcc扩展程序。我的问题是,如何处理标准符合C99中的这类问题? (加分问题:如何在C++11中执行此操作?)

注意:性能很重要,在迭代p时,应该有对齐的内存访问权限。取消引用循环中的指针,产生随机内存访问,不是一种选择。

3 个答案:

答案 0 :(得分:2)

我认为你最好的办法是放弃将数组包装在一个结构中的想法,咬紧牙关并自己分配一个2D数组。

这意味着您需要进行明确的索引编制,但无论如何都必须在幕后进行。

当谈到对齐时,如果你要访问每个n数组中的每个m数组元素,它可能无关紧要,最好使它们紧凑以最大化使用缓存。

类似的东西:

int *array = malloc(m * n * sizeof *array);

然后进行索引,只需执行:

// do something with the array
for(int i = 0; i < m; ++i)
{
  for(int j = 0; j < n; ++j)
    array[i * n + j] = j;
}

如果你非常担心这种乘法,请使用临时指针。当然,在分析它之后。

有时您会看到使用辅助宏来完成索引:

#define INDEX(a, n, i, j)  (a)[(i) * (n) + (j)]

然后你可以把最后一行写成:

INDEX(array, n, i, j) = j;

它有点笨拙,因为n当然需要一直进入那里。

答案 1 :(得分:1)

首先,在存在其他结构成员的情况下,将数组包装在结构中是唯一有意义的。如果没有其他struct成员,只需分配一个数组。

如果还有其他结构成员,则使用灵活数组成员来实现您的目标。灵活的数组成员在C标准中定义良好,并且适用于每个C99编译器。

// define struct dynamically
typedef struct{

    type_t the_reason_you_need_this_to_be_a_struct_and_not_an_array;
    int a[]; // flexible array member
}data_point_t;

// construct array of `m` elements
int m = 10;
size_t obj_size = sizeof(data_point_t) + n*sizeof(int);
data_point_t *p = malloc(m * obj_size);

答案 2 :(得分:0)

在C ++中,您当然可以像现在一样使用指针,但对于“适当的”C ++解决方案,唯一可行的解​​决方案是使用std::vector

struct data_point_t
{
    explicit data_point_t(const size_t sz)
        : a(sz)  // Construct the vector `a` with `sz` entries,
                 // each element will be zero initialized (`int()`)
    {}

    std::vector<int> a;
};

int main(int argc, char *argv[]){
    // Read `n`...
    int n = 10;  // Just example

    // Read `m`...
    int m = 10;  // Just example

    // Construct vector of `m` elements
    std::vector<data_point_t> p(m, data_point_t(n));

    // Here the vector `p` contains `m` elements, where each instance
    // have been initialized with a vector `a` with `n` elements
    // All fully allocated and initialized

    // Do something with the array
    // ...
}

这是有效的C ++ 03代码,所以除非你使用古老的东西(比如Turbo C ++),否则今天任何编译器都应该支持它。