2

3 つの正方形の 2 次元配列をバッファーに格納しようとしているので、連続した 1 つのメモリ ブロックを使用します。配列サイズが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 は double ポインター (配列の配列へのポインターであることを意味する) として宣言されているため、それぞれにサイズ r の配列を持ち、各要素がサイズ r の独自の個別の配列を指している必要があります。何か案は...

4

3 に答える 3

2

malloc'ing ポインターと malloc'ing doubles 自体を混同しています。次のように double を割り当てるだけです。

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

では、実際の行列はどこに行くのでしょうか?

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

off by one エラーをチェックしてください :) しかし、要点は double* と double の両方を malloc する必要はないということです。

于 2012-09-11T14:06:20.197 に答える
2

したがって、私の理解が正しければ、必要なのは 3 つのrxr配列 ( ab、およびc) ですが、3 つすべてを連続して格納する必要があります。基本的に、バッキング ストアは単一の 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、 、b、およびcを通常の のrxr配列であるかのように使用できdoubleます。

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" になります。それぞれ、backing_store[0]backing_store[1]およびbacking_store[2]rxr配列ですdouble

ほとんどのコンテキストでは、型 " N-element array of T" の式は、型 "pointer to T" の式に暗黙的に変換 ("減衰") され、その値は配列内の最初の要素のアドレスになることに注意してください。

したがって、式backing_store[0]は型 " r-element array of r-element array of double" から "pointer to r-element array of double" に変換され、これはたまたま の型でaあり、値は最初のサブ配列のアドレスです (これが発生します)。と同じになるbacking_store)。ここでも、添字演算子を適用すると暗黙的にポインターが逆参照されるため、の後に th 配列の th 要素がa[i][j]与えられます。 jia

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がコンパイル時不明で、(VLA をサポートしない C89 または C11 コンパイラを使用して) 可変長配列を使用できない場合は、少し複雑になる可能性があります。ここでは、 を 1 次元配列として扱い、1次元添字を各部分配列に計算します。backing_storedouble

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);

2 次元添字を使用するほどきれいではありませんが、動作するはずです。

于 2012-09-11T15:39:38.733 に答える
0

まず、2 次元配列は通常、ポインターを使用する特別な理由がない限り、行へのポインターとしてではなく、配列の配列として管理する方が適切です。このために、次のことができます。

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 標準への準拠に問題が生じます。さらに、コードは、 または のいずれかの 1 つの型の配列として扱われbufferます。ただし、必要なアドレス演算では、[設定時に [要素アドレス]、[ポインターのアドレスを double に設定する場合] へのポインターが必要になる場合があります。) 行へのポインターを使用するには、次のように割り当てることができます。doubledouble *doubledouble *

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 に答える