2

我正在尝试将三个方形二维数组存储到一个缓冲区中,因此我使用一个连续的内存块。如果数组大小是 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 的单独数组。有任何想法吗...

4

3 回答 3

2

您将 malloc'ing 指针与 malloc'ing doubles 本身混淆了。只需像这样分配双打:

double* all = (double*) malloc( 3*r*r*sizeof(double));

那么你的实际矩阵去哪里了?

double *p1 = all;
double *p2 = &all[r*r];
double *p3 = &all[2*r*r];

请检查一个错误:) 但关键是您不需要同时分配双 * 和双。

于 2012-09-11T14:06:20.197 回答
2

因此,如果我理解正确,您想要的是三个rxr数组(abc),但您希望它们三个都连续存储;本质上,后备存储将是一个 3 x rxr数组。

如果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,bc,就好像它们是 的常规rxr数组一样double

a[i][j] = ...;
printf("%f\n", b[x][y]);

等等

完成后,您只需要释放backing_store

free(backing_store);

为什么这行得通?

表达式backing_store的类型为“指向 的r-element 数组的r-element 数组的指针double。由于表达式backing_store[i]等价于*(backing_store + i),下标运算符隐式取消引用指针,因此表达式的类型为“ r-element array of r-element array of double”。每个, backing_store[0],backing_store[1]backing_store[2]是 的rxr数组double

请记住,在大多数情况下,“- Nelement array of T”类型的表达式被隐式转换(“decays”)为“pointer to T”类型的表达式,其值是数组中第一个元素的地址。

因此,表达式backing_store[0]从类型“ r-element array rof double”转换为“pointer to- relement array of double”,恰好是 的类型a,值是第一个子数组的地址(发生与 )相同backing_store。同样,应用下标运算符隐式地取消引用指针,因此在之后a[i][j]给出第th 数组的j第 th 元素。 ia

如果在编译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("%f\n", b[x*r+y]);

同样,您只需要backing_store在完成后释放:

free(backing_store);

不如使用二维下标漂亮,但它应该可以工作。

于 2012-09-11T15:39:38.733 回答
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视为一种类型的数组,或者doubledouble *。但是您需要的地址算术有时需要指向double[when setting元素地址],有时需要指向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];
于 2012-09-11T15:42:41.893 回答