我正试图将三个正方形的2d数组存储到一个缓冲区中,以便使用一个连续的内存块。如果数组大小是rxr,我的公式是:
buffer = (double*) malloc((r + r + r) * sizeof(double *) +
(r*r + r*r + r*r) * sizeof(double));
if(buffer == NULL) {
printf("out of memoryn");
return 0;
}
for(i = 0, j = 0; i < r; i++) {
a[i] = &buffer[j];
j+=r;
}
for(i = 0; i < r; i++) {
b[i] = &buffer[j];
j+=r;
}
for(i = 0; i < r; i++) {
c[i] = &buffer[j];
j+=r;
}
a = buffer[j];
b = buffer[j + r];
c = buffer[j + r + r];
正如你所看到的,我迷路了。a、 b,c被声明为双指针(意味着指向数组数组的指针),所以我希望每个元素都有一个r大小的数组,每个元素都指向它自己的r大小的单独数组。任何想法。。。
您将malloc’ing指针与malloc‘ing双打本身混淆了。只需分配双打,如:
double* all = (double*) malloc( 3*r*r*sizeof(double));
那么你的实际矩阵去哪儿了?
double *p1 = all;
double *p2 = &all[r*r];
double *p3 = &all[2*r*r];
请检查是否有一个错误:)但重点是你不需要同时用malloc掉double*和double。
因此,如果我理解正确的话,您想要的是三个r
x r
阵列(a
、b
和c
),但您希望这三个阵列都连续存储;基本上,后备存储器将是单个3 x r
x r
阵列。
如果r
的大小在编译时未知并且您正在C99或支持可变长度数组的C11实现中工作,则可以执行以下操作:
size_t r = ...;
double (*a)[r] = NULL;
double (*b)[r] = NULL;
double (*c)[r] = NULL;
double (*backing_store)[r][r] = malloc(3 * sizeof *backing_store);
if (!backing_store)
{
// panic and exit
}
a = backing_store[0];
b = backing_store[1];
c = backing_store[2];
然后,您可以使用a
、b
和c
,就好像它们是double
:的常规r
x r
阵列一样
a[i][j] = ...;
printf("%fn", b[x][y]);
等等。
完成后,您只需要释放backing_store
:
free(backing_store);
为什么这样做?
表达式backing_store
的类型为"pointer to r
-element array of r
-element array of double
。由于表达式backing_store[i]
等效于*(backing_store + i)
,下标运算符隐式取消引用指针,因此表达式的类型为"r
-element数组of r
-element阵列of double
".backing_store[0]
、backing_store[1]
和backing_store[2]
中的每一个都是double
的r
x r
阵列。
请记住,在大多数上下文中,类型为"N
-T
的元素数组"的表达式被隐式转换("decays")为类型为"指向T
的指针"的表达式,其值是数组中第一个元素的地址。
因此,表达式backing_store[0]
从类型"r
-r
-double
的元素数组"转换为"指向r
-double
的元素数组的指针",恰好是a
的类型,其值是第一个子数组的地址(恰好与backing_store
相同)。同样,应用下标运算符会隐式解引用指针,因此a[i][j]
在a
之后给出i
数组的第j
个元素。
如果r
在编译时是已知的(即,它是常量表达式),那么过程是相同的,您只需要声明变量r
:
#define R ...
double (*a)[R] = NULL;
double (*b)[R] = NULL;
double (*c)[R] = NULL;
double (*backing_store)[R][R] = malloc(3 * sizeof *backing_store);
if (!backing_store)
{
// panic and exit
}
a = backing_store[0];
b = backing_store[1];
c = backing_store[2];
如果r
在编译时是而不是,并且您没有可用的可变长度数组(使用C89或不支持VLA的C11编译器),那么它可能会变得有点混乱。在这里,我们将backing_store
视为double
的一维数组,并将一维下标计算到每个子数组中:
double *a = NULL;
double *b = NULL;
double *c = NULL;
double *backing_store = malloc(3 * r * r * sizeof *backing_store);
if (!backing_store)
{
// panic
}
a = backing_store;
b = backing_store + r * r;
c = backing_store + 2 * r * r;
a[i*r+j] = ...;
printf("%fn", b[x*r+y]);
同样,您应该只需要在完成后释放backing_store
:
free(backing_store);
没有使用二维下标那么漂亮,但它应该有效。
首先,二维数组通常作为数组的数组而不是作为行的指针来管理,除非有特殊的理由使用指针。为此,我们可以做:
double (*Memory)[r][r] = malloc(3 * sizeof *Memory);
// Now Memory points to three r-by-r arrays of double.
double (*a)[r] = Memory[0];
double (*b)[r] = Memory[1];
double (*c)[r] = Memory[2];
但是,如果要使用指向行的指针,则应该为指针分配空间,而不是为元素分配空间。(如果你不这样做,那么与C标准的一致性就会出现问题,尤其是在填充和对齐方面。此外,你的代码将buffer
视为一种类型的数组,double
或double *
。但你需要的地址算术有时需要指向double
的指针(当设置元素地址时),有时需要指向double *
的指针[将指针的地址设置为双精度时]。)要使用指向行的指针,可以使用以下方法进行分配:
double *(*PointerMemory)[r] = malloc(3 * sizeof *PointerMemory);
// PointerMemory points to three arrays of r elements of pointers to double.
double (*ElementMemory)[r][r] = malloc(3 * sizeof *ElementMemory);
然后您可以设置指向行的指针:
// Set a to point to the first array of r elements of pointers to double.
double *a[r] = PointerMemory[0];
// Initialize the elements of a to point to rows of the first r-by-r array of double.
for (i = 0; i < r; ++i)
a[i] = ElementMemory[0][i];
// Set b for the second array of pointers and the second array of double.
double *b[r] = PointerMemory[0];
for (i = 0; i < r; ++i)
b[i] = ElementMemory[1][i];
// Set c for the third arrays.
double *c[r] = PointerMemory[0];
for (i = 0; i < r; ++i)
c[i] = ElementMemory[2][i];