我有以下(不完整)功能:
/* Populates char* name with the named location of the ith (flat) element
* of an array with ndim dimensions where the length of each dimension
* is already stored in the int* dim.
*
* name: a pointer to where the name should be populated
* n: the base name of the array
* dim: an int[] containing the length of each dimension
* ndim: length of the dim array
* i: name of the iteration variable being used
**/
void populateName(char *name, const char *n, int *dim, int ndim, const char *i) {
strcpy(name, n);
char *loc = (char*)(name + strlen(n));
char *curr;
for (int k = 0; k < ndim; k++) {
...
sprintf(loc, "[%s]", curr);
loc += strlen(loc);
}
}
for循环中的“...”应该包含哪些内容?例如,使用:
调用populateName()int dim[2] = {3, 4};
char name[1024];
populateName(name, "x", dim, 2, "i");
应该会产生类似的结果:
name = "x[i / 3][i % 4]"
或用于访问定义为:
的数组中的第i个位置的其他有效名称int x[3][4];
上下文:我正在编写一个C程序,它生成C程序,根据用户定义的数据类型和用IDL编写的规则过滤大量数据。
编辑:一个返回包含数组中位置/坐标的元组的python函数可能会让我朝着正确的方向前进。特别是下面的数组应该让每个元素对应于它在数组中的平面位置(在这里使用pylab):
In [14]: x
Out[14]:
array([[[ 0, 1, 2],
[ 3, 4, 5]],
[[ 6, 7, 8],
[ 9, 10, 11]],
[[12, 13, 14],
[15, 16, 17]]])
In [15]: x.flat.copy()
Out[15]:
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17])
答案 0 :(得分:3)
解决像这样的问题的好方法是尝试一些例子。请考虑以下图片,其中显示了3D阵列x[2][3][5]
的内存布局:
我们如何将偏移14转换为位置x[0][2][4]
?好吧,首先,我们看到每个x[i]
包含15(3 * 5)个块,所以首先我们通过计算整数除法14/15 = 0来确定14属于哪个块。所以,偏移14位于x[0]
内。
我们现在可以应用相同的方法。 x[i][j]
包含5个块,因此偏移量14属于块号14/5 = 2.实际上,正确的计算是(14/5)%3,正如我们将看到的偏移量18.最后,{{{ 1}}包含单个块,因此最后一个索引由14%5给出。可以这样想:我们正在解释这些内存块,就好像它们在每一步都有不同的大小。首先,我们假设所有内容都分为15个元素。然后,我们假设所有内容都被划分为5个元素。
您可以使用此示例,并看到偏移18映射到x[i][j][k]
,因为18/15 = 1; (18/5)%3 = 0,18%5 = 3.
可以看出,一般情况是对于维x[1][0][3]
,我们将内存布局解释为在n
块中组织,其中j
是每个j
的产物维度大于n
,因此我们必须将位置(i/j)%n
编入索引。
这是我的实施:
void populateName(char *name, const char *n, int *dim, int ndim, const char *i) {
strcpy(name, n);
char *loc = (char*)(name + strlen(n));
int j;
int *mul = malloc(sizeof(int)*ndim);
mul[ndim-1] = 1;
/* Compute cumulative multipliers array */
for (j = ndim-2; j >= 0; j--) {
mul[j] = mul[j+1] * dim[j+1];
}
for (j = 0; j < ndim; j++) {
loc += sprintf(loc, "[(%s/%d)%%%d]", i, mul[j], dim[j]);
}
free(mul);
}
如您所见,它使用累加的乘数数组,其中mul[i]
包含大于i
的每个维度的乘积。
顺便说一下,你不需要curr
;由于sprintf
会返回打印的字符数,因此我们只需移动相同金额的loc
。它比strlen
之后重复调用sprintf
更有效率。
我没有太多时间来测试这个,但是根据我展示的例子,我得到了这个:
x[(i/15)%2][(i/5)%3][(i/1)%5]
哪个看起来正确。这是一个示例程序:
int main()
{
int dims[] = { 2, 3, 5, 7, 9 };
char name[1024];
populateName(name, "x", dims, 5, "i");
printf("%s\n", name);
return 0;
}
打印:
x[(i/945)%2][(i/315)%3][(i/63)%5][(i/9)%7][(i/1)%9]
读取任意n维数组变得比较棘手,但原理总是一样的。