1

動的に割り当てられた連続した3D配列をCコードで実装しようとしています。配列のnetCDF出力に依存しているため、配列は連続している必要があります。ここで、StackOverFlowSolutionに投稿されたソリューションを採用しました。これは、配列を動的に割り当ててインデックスを作成する場合に問題なく機能します...ただし、netCDFが配列を出力すると、2番目のインデックスサイズ(jcount)としてスケーリングされるように見えるオフセットがあります。変更された関数は次のとおりです。

void*** newarray(int icount, int jcount, int kcount, int type_size)
{
  int i,j,k;
  void*** iret = (void***)malloc(icount*sizeof(void***)+icount*jcount*sizeof(void**)+icount*jcount*kcount*type_size);
  void** jret = (void**)(iret+icount);
  char* kret = (char*)(jret+icount*jcount);
  for(i=0;i<icount;i++)
  {
    iret[i] = &jret[i*jcount];
  }
  for(i=0;i<icount;i++)
  {
    for(j=0;j<jcount;j++)
    {
      jret[i*jcount+j] = &kret[i*jcount*kcount*type_size+j*kcount*type_size];
    }
  }
  return iret;
}

この関数を正しく理解すると、iretには、iretを構成する3Dポインター(最初のインデックス)、jretを構成する2Dポインター(2番目のインデックス)、およびkretを構成する実際の値用のスペースが割り当てられます。次に、2D jretポインターは、iretの2D配列セクションに関連付けられます。次に、kretについても同じことが行われます。次に、iretのすべてのアドレスは、jretの各セクションの最初の値を指します。次に、jretの各アドレスがkretの最初のアドレスを指します。

ちなみに、私の配列のプリプロセッサで定義された値では、すべてが正常に機能していました。また、コードでいくつかのprintfステートメントを使用して、配列の数値をチェックすると、それらはすべて正しくインデックス付けされているように見え、コードは正しく実行されます。出力は、配列の非連続メモリストレージの結果であるように見えます。

私は次の形式の構造を持っています:

typedef struct
{
  double ***test;
} STRUCT_TYPE;

次に、これを使用して割り当てます

mhd    = (STRUCT_TYPE *)  malloc(sizeof(STRUCT_TYPE));
mhd.test = (double***) newarray(101,7,101,sizeof(double));

これはnetCDFの問題かもしれません...しかし、私の割り当てルーチンが問題ではないことを知りたいだけです。

4

2 に答える 2

1

これは、実際にはLazerの回答の質問に対する回答です。

これにより、Cが配列にメモリを割り当てるとき、最初に値を格納するために使用されるメモリを割り当て、次に多次元配列に構造を提供するポインタにメモリを割り当てると思います。

多分誰かが私のためにこれを片付けることができますか?

Cには非常に根本的な違いがあります

double arr[A][B][C];

double ***ptr;

どちらも。でインデックスを付けることができますがx[i][j][k]、結果のマシンコードは大きく異なります。

double arr[A][B][C]CdoubleのB配列のA配列の配列です。コードでこれをとしてインデックス付けする場合arr[i][j][k]、コンパイラはそれを。((i*B + j)*C + k)*sizeof(double)の先頭からのバイトのオフセットに変換しますarr。ここには中間ポインターは含まれていませんが、次元BとCはコンパイラーに認識されている必要があります。

'double *** ptr'は、double(の配列の開始)へのポインター(の配列の開始)へのポインター(の配列の開始)へのポインターです。コードでこれをとしてインデックス付けする場合ptr[i][j][k]、コンパイラーは各インデックス作成操作を個別に実行し、すべての中間ポインターに従う以外に選択肢はありません。これにより、次のようなコードになります

temp1 = ptr[i];
temp2 = temp1[j];
result = temp2[k];

このnewarray関数は、これらすべてのコンポーネント配列を単一のメモリブロックから切り出しますが、これは言語では必要なく、コンパイラはこれが行われていることを認識していないため、すべてのコンポーネント配列を次のように処理する必要があります。互いに完全に独立しています。

于 2010-10-26T09:20:55.243 に答える
0

さて、私は修正を見つけました...それはもっと慣習的なものですが。最初にコードを設計したときは、プリプロセッサディレクティブを使用して配列サイズを宣言しました。次に、構造内の各配列を宣言しました。メモリを節約するために、構造体へのポインタをサブ関数に渡すだけです。これは、main()ルーチンの外部で要素を参照する場合、次のようなものを使用したことを意味します。

grid->x;

今、私はxの各要素を次のように参照します

grid->x[i][j][k];

もちろん、netCDF関数が格納しようとしている変数へのポインターを必要としたとき、私はそれを渡しました

grid->x

ただし、この新しいメモリ割り当て関数を使用して、これを関数に渡すと、実際には、さまざまなポインタ用に確保されているメモリ空間の最初のアドレスを渡します。本質的に、私はメモリ内の間違ったアドレスへのポインタを渡していました。私がしなければならなかったのは、渡された引数を次のように変更することだけです。

&grid->x[0][0][0]

そして、適切な配列出力を取得します。これにより、Cが配列にメモリを割り当てるとき、最初に値を格納するために使用されるメモリを割り当て、次に多次元配列に構造を提供するポインタにメモリを割り当てると思います。

多分誰かが私のためにこれを片付けることができますか?

于 2010-10-25T18:41:55.740 に答える