基本问题是:
对于期望指针到指针的代码,该指针将像二维数组一样进行语法索引,是否有有效的方法可以使用单个分配创建这样的数组†
虽然从表面上看,我似乎在问如何做到这一点(就像这个问题一样),但我已经明白了如何做到(见下文)。问题是可能存在对齐问题&ddagger
正文的其余部分描述了一些替代方案,然后解释了所讨论的方法。
†奥拉夫指出,指向指针的指针不是二维数组。这个问题的前提是,第三方代码期望传入一个指向指针的指针,而第三方编码会将其索引为二维数组
&d达格;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 **
指针表方法的问题在于可能存在对齐问题。只要数组的任何类型都没有比指针更严格的对齐要求,代码就应该可以工作。
以上内容是否始终有效?如果没有,是否有一种有效的方法来实现指针到指针风格的二维数组的单个分配?
好吧,你的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);