我正在尝试将三个正方形的2d数组存储到缓冲区中,因此我使用了一个连续的内存块。如果数组大小是rxr,我的公式是:
buffer = (double*) malloc((r + r + r) * sizeof(double *) +
(r*r + r*r + r*r) * sizeof(double));
if(buffer == NULL) {
printf("out of memory\n");
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的数组。任何想法......
答案 0 :(得分:2)
你把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。
答案 1 :(得分:2)
所以,如果我理解正确,你想要的是三个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
,就好像它们是r
x r
数组double
一样:< / p>
a[i][j] = ...;
printf("%f\n", b[x][y]);
等。
完成后,您只需要免费backing_store
:
free(backing_store);
为什么这样做?
表达式backing_store
具有类型“指向r
的指针 - r
的元素数组 - double
的元素数组。由于表达式backing_store[i]
等效于*(backing_store + i)
,下标运算符隐式取消引用指针,因此表达式的类型为“r
- r
的元素数组 - double
的元素数组”。每个{ {1}},backing_store[0]
和backing_store[1]
是backing_store[2]
的{{1}} x r
数组。
请记住,在大多数情况下,类型为“r
- double
的元素数组”的表达式被隐式转换(“衰变”)为“指向N
的指针” “,它的值是数组中第一个元素的地址。
因此,表达式T
从类型“T
- backing_store[0]
的元素数组 - r
的元素数组”转换为“指向r
的指针-lelement数组double
“,恰好是r
的类型,值是第一个子数组的地址(恰好与double
相同)。同样,应用下标运算符会隐式取消引用指针,因此a
会在backing_store
之后提供a[i][j]
数组的j
元素。
如果i
在编译时已知(即,它是常量表达式),那么程序是相同的,你只是没有声明变量a
:
r
如果r
t支持VLA),然后它会变得有点混乱。在这里,我们将#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
的一维数组,并在每个子数组中计算一维下标:
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("%f\n", b[x*r+y]);
不如使用2-d下标那么漂亮,但它应该有效。
答案 2 :(得分:0)
首先,二维数组通常更好地作为数组的数组进行管理,而不是作为指针的指针,除非有特殊的理由使用指针。为此,我们可以这样做:
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
或{{1}但是你需要的地址算法有时需要指向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);