【发布时间】:2016-07-28 01:30:21
【问题描述】:
基本问题是:
对于需要 指向指针的指针 的代码,该指针将像二维数组一样在语法上被索引,是否有 有效 方法来使用单个分配创建这样的数组?†
从表面上看,我似乎在询问如何做到这一点(如在this question 中),但我已经了解如何做到这一点(见下文)。问题是可能存在对齐问题。‡
文本的其余部分描述了一些替代方案,然后解释了所讨论的方法。
† Olaf 指出指向指针的指针不是二维数组。问题的前提是 3rd 方代码期望传入一个指向指针的指针,3rd 方代码会将其索引为二维数组。
‡ 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 **
指针表方法的问题是可能存在对齐问题。只要数组的任何类型没有比指针更严格的对齐要求,代码就可以工作。
以上预期总是有效的吗?如果没有,是否有一种有效的方法来为 pointer to pointer 样式的二维数组实现单次分配?
【问题讨论】:
-
int **之类的东西不是也不能是二维数组(对于更高维度也是如此)。它也可以不指向一个。所以你的问题毫无意义。使用现代 C 编译器,您将拥有 VLA。不要试图骑死马,这只会导致挫败感——充其量。 -
看起来同一个问题的答案在这里stackoverflow.com/questions/8740195/…
-
@ErikNyquist 我的问题是关于指针表后面的数组项的对齐。
-
@Olaf:VLA 在 C.99 中是必需的,但在 C.11 中变为可选。显然,我说的不是严格定义的二维 C 数组,而是一个可以像二维一样被索引的指针。
-
@jxh:我没有说使用 C11,而是使用 现代 C 编译器,这是有充分理由的。将强制性(且非常有用的)功能设为可选是委员会最糟糕的决定。这绝对违反了委员会的普遍做法,它甚至仍然允许省略函数声明(它们必须生成警告,但它没有错误)或仍然允许通过
char *进行别名 - 尽管void *等。某编译器供应商的不良影响,超过 17 年仍然无法提供兼容的编译器。
标签: c pointers multidimensional-array malloc