• ベストアンサー

3次元配列の動的確保

2次元配列は、 // 動的確保 int **mat = new int*[row]; for(i = 0; i < row; i++) mat[i] = new int[col]; //解放 for(i = 0; i < row; i++) delete [] mat[i]; delete [] mat; で、生成と開放はできたのですが、3次元となると、途端にわからなくなります。 かれこれ1時間半は試行錯誤はしているのですが、たどり着きそうにありません。 どなたかご教授願います。

質問者が選んだベストアンサー

  • ベストアンサー
  • ency
  • ベストアンサー率39% (93/238)
回答No.8

No6 ency です。 > delete[][] というのがミソでしょうか。 > 恥ずかしながらはじめて見ました。 lachesis-r さんはぜんぜん恥ずかしくないです。 逆に、恥ずかしいのは私です。。。 該当箇所は、 delete[] mat[i][j] で置き換えてください。 # 私もなんて恥ずかしいミスをしてしまったのか・・・。

lachesis-r
質問者

補足

ありがとうございます。 残念ながら、コンパイルできません。 試行錯誤してみたのですが、なかなかうまくいきませんでした。

その他の回答 (8)

  • Soli
  • ベストアンサー率11% (7/61)
回答No.9

No7です。 > 1次元配列に置き換えるということですね。 > これだと要素数が2のn乗でない場合には遅くなるかもしれませんね。 > (すみません。試していません) > クラスにして要素へのアクセスを[]演算子でできるようにして・・・という感じでしょうか? 1次元にすると各要素ごとのメモリ確保・解放が出来ないので 常に最大量食いっぱなしなのが美しくないですけどね^^; 処理が遅い、というのはアセンブラに直してみると解ると思いますが、 値を取るたびに乗算が複数回行われるので 3次配列に比べて遅いかなぁ、と思って書きました。 #すみません試してません… 2のn乗でない場合も遅いかもなんですね。 場合によって使い方はマチマチなのですが、 手っ取り早くそのまま使ってることが多いです。 色々端折ってますが以下のような感じです。 void CHogeHoge::Create3DArray( int nRangeX, int nRangeY, int nRangeZ ) { m_pBuffer = new int[ nRangeX * nRangeY * nRangeZ ]; m_nRangeX = nRangeX; // 配列の一次要素数 [ ][ ][*] m_nRangeY = nRangeY; // 配列の二次要素数 [ ][*][ ] m_nRangeZ = nRangeZ; // 配列の三次要素数 [*][ ][ ] } int CHogeHoge::GetValue( int nAxisX, int nAxisY, int nAxisZ ) { return m_pBuffer[ nAxisX + nAxisY * m_nRangeX + nAxisZ * ( m_nRangeX * m_nRangeY ) ]; }

lachesis-r
質問者

お礼

試してみました。 2次元配列の場合、要素数が2^nとそうでない場合とでは30%程度パフォーマンスが落ちるようです。 乗算のコストとシフトのコストの差、よりはマシですが、命令スケジューリングが効いているのかもしれませんね。 なお、BCB6でMMXのSSE2を使って乗算+右シフトをasmで書いた場合とも比較しましたが、SSE2は50%程度までしか早くなりませんでした。 なかなかうまくいかないものです。

  • Soli
  • ベストアンサー率11% (7/61)
回答No.7

私のやり方が正しいかわかりませんが・・・ いつも多次元配列を考えるのが面倒なので、 int *P = new int[ x * y * z ]; // int P[z][y][x]のようにしたい場合 のように確保して、 int I = P[ X + Y*x + Z*(x*y) ]; // X,Y,Z は取り出したいデータが入ってる各軸の座標 のように取り出してます。 ご参考までに。 #処理が遅いかも…?

lachesis-r
質問者

お礼

ありがとうございます。 1次元配列に置き換えるということですね。 これだと要素数が2のn乗でない場合には遅くなるかもしれませんね。 (すみません。試していません) クラスにして要素へのアクセスを[]演算子でできるようにして・・・という感じでしょうか?

  • ency
  • ベストアンサー率39% (93/238)
回答No.6

解決方法というよりも、C の配列の話をします。 ここから、lachesis-r さんのやり方でうまくいかない理由を汲み取ってもらえれば良いのですけど。。。 No4 Tacosan さんの回答がきちんと動作するか、未確認ですが、動作するのであれば、配列を使った解決手段としてはほぼ唯一ではないでしょうか。 C の配列はコンパイラが先頭要素へのポインタに読み替えますが、これは再帰的には適用されません。 つまり、配列の配列の配列 (3次元配列) では、配列の配列の先頭要素へのポインタに読み替えられますが、さらにそこからポインタへの読み替えは起こりません。 つまり、以下のようになるわけです。 [例] ------------------------------------------------ // NEW int **mat = new int*[elem2][elem1] for ( i = 0; i < elem2; i++ ) { for ( j = 0; j < elem1; j++ ) { mat[i][j] = new int[elem3]; } } // DELETE for ( i = 0; i < elem2; i++ ) { for ( j = 0; j < elem1; j++ ) { delete [][] mat[i][j]; } } delete mat; ------------------------------------------------ ですので、すでに回答にある方法を参考にするほうが、有用だと思います。 # C++ 自体よく知らないものでして。。。 $ うまい解決方法は、詳しい方々におまかせします。。。 とりあえず参考程度に。。。

lachesis-r
質問者

補足

ありがとうございます。 いろんな方法があるものですね・・・ 少し整理したいのですが、仕事が忙しくなかなか空き時間がとれません。 delete[][] というのがミソでしょうか。恥ずかしながらはじめて見ました。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.5

> vectorはコンパイル速度も実行速度も犠牲になりますし、アルゴリズムも範囲チェックも不要なので、出来れば避けたいと思います。 実際に計測していただければわかると思いますが、vectorを使っても実行速度はほとんど変わらないはずです。(ライブラリの実装にもよるところも多少ありますし、CINTのようなインタープリタであればやはり遅くなるでしょうが...) > これだと、添え字の異なる(型が同一の)3次元配列をひとつの関数で受けられません。 > 例えば、a[10][20][30]とb[60][70][10]のような関数を同一の関数に渡す事ができません。 > > 何か良い方法がありますか? template <int M, int N> void func(int (*p)[M][N]); のようにすれば、1つの関数で済みます。(実体は複数出来ます)

lachesis-r
質問者

お礼

なんとかテスト再開できました。 A,Bが動的2次元配列、AVがvecorによる2次元配列で、 for(int i=0;i<count;i++) for(int y=0;y<DIM;y++) for(int x=0;x<DIM;x++) A[y][x]= A[y][x] *B[DIM][DIM]/256; for(int i=0;i<count;i++) for(int y=0;y<DIM;y++) for(int x=0;x<DIM;x++) AV[y][x]= AV[y][x] *B[DIM][DIM]/256; これだと 前者: 805.275ms 後者: 1833.780ms でした。 (DIM:512、count:1000) Pen4 3.2G WinXPPro BCB6Pro ふと思ったのは、vectorはイテレータを使わないと早くならないのかしら?ということですが、そこまで手が回りませんでした^^; ※コンパイル速度は遅いと感じるほどには変わりませんでした。 ※vectorは要素チェックは行いませんね。不適切な発言でした。

lachesis-r
質問者

補足

ありがとうございます。 今、仕事がバタバタしておりまして、手が空き次第、試してみます。 実行速度については、以前の予備テストのおぼろげな記憶でして、不適切な発言だったかもしれません。 これについても、再度確認します。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

// 確保 int ***mat; mat = new int **[a]; mat[0] = new int *[a*b]; mat[0][0] = new int [a*b*c]; for (int i = 0; i < a; i++) { mat[i] = mat[0] + i*b; mat[i][0] = mat[0][0] + i*b*c; for (int j = 0; j < b; j++) { mat[i][j] = mat[i][0] + j*c; } } // 開放 delete [] mat[0][0]; delete [] mat[0]; delete [] mat; くらいかなぁ? 実行してないので動作の保証はできませんが....

lachesis-r
質問者

お礼

ありがとうございます。 動きました。 このようにする方法もあるんですね。 勉強になります。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

学習目的であれば別ですが、実用を考えると次のようにした方がよいと思います。 要素数が固定でよい場合... int (*p)[M][N] = new int[num][M][N]; 各次の要素数が可変の場合... std::vector<std::vector<std::vector<int> > > a; なるべくstd::vectorを使うことをお薦めします。 (解放の手間も省けることですし...)

lachesis-r
質問者

お礼

>a[10][20][30]とb[60][70][10]のような関数を a[10][20][30]とb[60][70][10]のような「配列」を です。申し訳ありません。

lachesis-r
質問者

補足

ありがとうございます。 vectorはコンパイル速度も実行速度も犠牲になりますし、アルゴリズムも範囲チェックも不要なので、出来れば避けたいと思います。 int (*p)[M][N] = new int[num][M][N]; の使い方も試してみました。 これだと、添え字の異なる(型が同一の)3次元配列をひとつの関数で受けられません。 例えば、a[10][20][30]とb[60][70][10]のような関数を同一の関数に渡す事ができません。 何か良い方法がありますか? (未だに***p でのdeteteがうまくいかない・・・)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

2次元でできれば 3次元だってすぐだと思うけど.... * が 1個増えるだけ (new/delete も増えるけど) でしょ?

  • kenipi
  • ベストアンサー率29% (44/150)
回答No.1

こんなところをご覧になってはいかがでしょうか。

参考URL:
http://sometime.minidns.net/~ccgi/pointer_array.html

関連するQ&A

専門家に質問してみよう