電子書籍の厳選無料作品が豊富!

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時間半は試行錯誤はしているのですが、たどり着きそうにありません。
どなたかご教授願います。

A 回答 (9件)

No6 ency です。



> delete[][] というのがミソでしょうか。
> 恥ずかしながらはじめて見ました。

lachesis-r さんはぜんぜん恥ずかしくないです。
逆に、恥ずかしいのは私です。。。

該当箇所は、

delete[] mat[i][j]

で置き換えてください。

# 私もなんて恥ずかしいミスをしてしまったのか・・・。

この回答への補足

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

補足日時:2005/02/25 11:18
    • good
    • 0

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 ) ];
}
    • good
    • 1
この回答へのお礼

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

なお、BCB6でMMXのSSE2を使って乗算+右シフトをasmで書いた場合とも比較しましたが、SSE2は50%程度までしか早くなりませんでした。
なかなかうまくいかないものです。

お礼日時:2005/02/25 13:28

私のやり方が正しいかわかりませんが・・・



いつも多次元配列を考えるのが面倒なので、

int *P = new int[ x * y * z ];
// int P[z][y][x]のようにしたい場合

のように確保して、

int I = P[ X + Y*x + Z*(x*y) ];
// X,Y,Z は取り出したいデータが入ってる各軸の座標

のように取り出してます。
ご参考までに。

#処理が遅いかも…?
    • good
    • 0
この回答へのお礼

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

お礼日時:2005/02/25 11:10

解決方法というよりも、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++ 自体よく知らないものでして。。。
$ うまい解決方法は、詳しい方々におまかせします。。。

とりあえず参考程度に。。。

この回答への補足

ありがとうございます。

いろんな方法があるものですね・・・
少し整理したいのですが、仕事が忙しくなかなか空き時間がとれません。

delete[][] というのがミソでしょうか。恥ずかしながらはじめて見ました。

補足日時:2005/02/24 12:08
    • good
    • 0

> vectorはコンパイル速度も実行速度も犠牲になりますし、アルゴリズムも範囲チェックも不要なので、出来れば避けたいと思います。



実際に計測していただければわかると思いますが、vectorを使っても実行速度はほとんど変わらないはずです。(ライブラリの実装にもよるところも多少ありますし、CINTのようなインタープリタであればやはり遅くなるでしょうが...)

> これだと、添え字の異なる(型が同一の)3次元配列をひとつの関数で受けられません。
> 例えば、a[10][20][30]とb[60][70][10]のような関数を同一の関数に渡す事ができません。
>
> 何か良い方法がありますか?

template <int M, int N> void func(int (*p)[M][N]);

のようにすれば、1つの関数で済みます。(実体は複数出来ます)

この回答への補足

ありがとうございます。

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

補足日時:2005/02/24 12:06
    • good
    • 0
この回答へのお礼

なんとかテスト再開できました。
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は要素チェックは行いませんね。不適切な発言でした。

お礼日時:2005/02/25 11:04

// 確保


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;

くらいかなぁ? 実行してないので動作の保証はできませんが....
    • good
    • 0
この回答へのお礼

ありがとうございます。
動きました。

このようにする方法もあるんですね。
勉強になります。

お礼日時:2005/02/22 18:03

学習目的であれば別ですが、実用を考えると次のようにした方がよいと思います。



要素数が固定でよい場合...
int (*p)[M][N] = new int[num][M][N];

各次の要素数が可変の場合...
std::vector<std::vector<std::vector<int> > > a;

なるべくstd::vectorを使うことをお薦めします。
(解放の手間も省けることですし...)

この回答への補足

ありがとうございます。

vectorはコンパイル速度も実行速度も犠牲になりますし、アルゴリズムも範囲チェックも不要なので、出来れば避けたいと思います。

int (*p)[M][N] = new int[num][M][N];
の使い方も試してみました。

これだと、添え字の異なる(型が同一の)3次元配列をひとつの関数で受けられません。
例えば、a[10][20][30]とb[60][70][10]のような関数を同一の関数に渡す事ができません。

何か良い方法がありますか?

(未だに***p でのdeteteがうまくいかない・・・)

補足日時:2005/02/22 09:07
    • good
    • 0
この回答へのお礼

>a[10][20][30]とb[60][70][10]のような関数を

a[10][20][30]とb[60][70][10]のような「配列」を

です。申し訳ありません。

お礼日時:2005/02/22 09:16

2次元でできれば 3次元だってすぐだと思うけど....



* が 1個増えるだけ (new/delete も増えるけど) でしょ?
    • good
    • 0

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



参考URL:http://sometime.minidns.net/~ccgi/pointer_array. …
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!