基本问题是:
对于需要指向指针的指针的代码,它将在语法上像二维数组一样编入索引,是否有 有效 方式使用单个分配创建这样的数组?†
虽然从表面上看,我似乎要求如何这样做(如在this question中),我已经明白了如何做到(见下文)。问题是可能存在对齐问题。‡
本文的其余部分描述了一些替代方案,然后解释了所讨论的方法。
†奥拉夫指出一个指向指针的指针不是一个二维数组。问题的前提是第三方代码需要传入指针的指针,第三方代码会将其索引为二维数组。
‡ErikNyquist提出了一个可能的副本,解释了如何执行这样的分配,但我质疑该技术在数据对齐方面的有效性。
如果我需要动态分配多维数组,我通常会使用单个分配调用来避免在以后想要释放数组时进行迭代。
如果VLA可用,我可能会这样编码:
int n, m;
n = initialize_n();
m = initialize_m();
double (*array)[m] = malloc(n * sizeof(*array));
array[i][j] = x;
如果没有VLA,我要么依赖于数组访问结构上的宏,要么为需要**
二维数组样式的代码添加指针表空间。宏观方法如下:
struct array_2d {
int n, m;
double data[];
};
// a2d is a struct array_2d *
#define GET_2D(a2d, i, j) (a2d)->data[(i) * x->n + (j)]
struct array_2d *array = malloc(sizeof(*array) + n * m * sizeof(double));
array->n = n;
array->m = m;
GET_2D(array, i, j) = x;
指针表方法更复杂,因为它需要一个循环来初始化表。
struct array_p2d {
int n, m;
double *data[];
};
#define GET_P2D(a2d, i, j) (a2d)->data[i][j]
struct array_p2d *array = malloc(sizeof(*array) + n * sizeof(double *)
+ n * m * sizeof(double));
for (k = 0; k < n; ++k) {
array->data[k] = (double *)&array->data[n] + k * m;
}
GET_P2D(array, i, j) = x;
// array->data can also be passed to a function wanting a double **
指针表方法的问题是可能存在对齐问题。只要数组的类型没有比指针更严格的对齐要求,代码就可以工作。
上述预期总是有效吗?如果没有,是否有一种有效的方法来实现指向指针样式二维数组的指针的单一分配?
答案 0 :(得分:1)
好吧,你的malloc
分配保证是对齐的(除非你使用非标准对齐),所以你需要做的就是将指针表大小向上舍入到数据的对齐段:
const size_t pointer_table_size = n * sizeof(double *);
const size_t data_segment_offset = pointer_table_size +
((_Alignof(double) - (pointer_table_size / _Alignof(double))) % _Alignof(double));
double **array = malloc(data_segment_offset + (n * m * sizeof(double));
double *data = (double **)(((char **) array) + data_segment_offset);
for (int i = 0; i != n; ++i)
array[i] = data + (m * i);