• 締切済み

動的メモリの確保の仕方を教えて下さい。

プログラミングの初心者なのですが、現在256x256x100のバイナリファイルを読み込もうとしているのですが、下のように書くとエラーになってしまいます。動的メモリの確保を行えば、上手くいくと思うのですが。。どなたか教えて頂けないでしょうか?どうぞよろしくお願いします。 const short int SIZE=256; const short int SLICE=100; signed short int matrix[SLICE][SIZE][SIZE]; for(int i=0; i<SLICE; i++){ for(int j=0;j <SIZE; j++){ for(int k=0;k<SIZE; k++){ fin.read((char*) &matrix[i][j][k],sizeof(signed short int)); cout<< matrix[i][j][k]<<endl; } } }

みんなの回答

回答No.7

追記。 例で提示した fin.read((char*) &matrix[(i*SIZE+j)*SIZE+k],sizeof(signed short int)); なんだけど「正しく読める確率は50%」なので、注意して下さい。 上記のプログラムの意味は「signed short intの場所に、signed short intのサイズ分、読み込め」って意味なんだけど、実は「ファイルの中身が、signed short intの並び順でバイトデータが並んでいるとは限らない」ので、読めるかどうかは「確率50%」になります。 signed short intに16進数で0x1234と言うデータが入っている時、コンピューターの種類によって、メモリ上に 0x12,0x34 と言う順番で「そのまま並べるコンピューター」と 0x34,0x12 と言う順番で「上位と下位をひっくり返して並べるコンピューター」と、2種類あるのです。 CT画像を生成した機器が、0x1234と言うデータをファイルに保存する時に 0x12,0x34 と言う順番で「ひっくり返さずそのまま」ファイルに保存した場合、それを fin.read((char*) &matrix[(i*SIZE+j)*SIZE+k],sizeof(signed short int)); とかで読むと、メモリ上には 0x12,0x34 と言う順番で「常にひっくり返さずそのまま」でデータが置かれます。 もし「上位と下位をひっくり返して並べるコンピューター」で読み込むと、メモリ上には「ひっくり返さずそのまま」で 0x12,0x34 という並びで置かれてますから、コンピューターは「上位と下位をひっくり返して解釈する」ので、このデータは0x3412として解釈されます。 本当のデータは「0x1234」なのに「0x3412」として読んでしまうのです。 「メモリ上に置くときは、上下をひっくり返して置く」というお約束があるコンピューターで「ファイルから読み込んでメモリに置く時に、上下をひっくり返してない」のですから、当然「上下を逆に解釈してしまう」のです。 CT画像を生成した機器が0x1234と言うデータをファイルに保存したのに、別のコンピューターで読み込むと、0x3412として解釈されたり、0x1234として解釈されたりするのです。 回答番号No.2の人が >>fin.read((char*) &matrix[i][j][k],sizeof(signed short int)); >このコードが何を意図しているか、説明していただけますか? と聞いた真意は、上記のように「ちゃんと読める確率が50%なのは、理解出来ていますか?」と聞きたかったのだと思われます。 詳しくは「エンディアンの違い」や「バイトオーダー」でネット検索してみて下さい。

momoharata
質問者

お礼

私のパソコンはintelでしたので、無事読むことが出来ました。 まだまだ、分からない事ばかりなので勉強になりました。 この機会に「エンディアンの違い」や「バイトオーダー」なども勉強してみたいと思います。どうもありがとうございます!

回答No.6

>医療用のCT画像(256pixelx256pixelx100枚)バイナリ形式で保存されているデータを処理処理したくて やっぱり。もしかしたら「100枚分を一気に読み込む必要は無い」のでは? 「1枚分(256×256)の2次元配列を1個分」用意して、毎回、その配列に読み込むのを100回繰り返せば、目的を達成できたりしませんか? もう一度「100枚のCT画像が、すべて同時に必要かどうか?」を考え直してみて下さい。

回答No.5

追記。 提示した例で、セミコロンが1つ抜けました。 どこに抜けたのかは宿題にしておきますので、どこに抜けたのか考えて、修正してみて下さい。

回答No.4

>ただ、ここで定義しているSLICE値を1~4までなら上手く動作します。 >これ以上SLICE値が増加するとエラーになってしまいます。 エラーの状況から察するに、matrixは「関数内で宣言されたオート変数」だと推測します。 オート変数は、通常、スタック領域に生成されます。 スタック領域は、通常、256キロバイトとか512キロバイトとか、比較的に小さいサイズに設定されています。 スタック領域が、もし仮に512キロバイトになっていると仮定した場合、signed short intを4×256×256個分確保すると、それだけで512キロバイトになるのでスタック領域が溢れます。 スタック領域から多少溢れただけでは、未使用メモリを侵食するだけなので「問題無く動いているように見える」ために、問題が発覚しません。 しかし5×256×256個分確保すると、スタック領域を大幅に越え、他の目的で使用しているメモリを壊し始めるので「実行時に問題が発生したため~」のエラーが出ます。 なので「多分、安全に動作するのは、SLICEが3まで」です。 動的に確保するなら、以下のようにします。 const short int SIZE=256; const short int SLICE=100; signed short int *matrix matrix = (signed short int *)malloc(sizeof(signed short int)*SLICE*SIZE*SIZE); //動的に確保する if (matrix == NULL) return; //メモリが足りない for(int i=0; i<SLICE; i++){ for(int j=0;j <SIZE; j++){ for(int k=0;k<SIZE; k++){ fin.read((char*) &matrix[(i*SIZE+j)*SIZE+k],sizeof(signed short int)); cout<< matrix[(i*SIZE+j)*SIZE+k]<<endl; } } } free(matrix); //使い終わったら開放する もし「メモリが足りなくてif文で跳ねられてしまう」としたら「実メモリが足りないので、そのパソコンでは動作不可能」です。 その場合「3次元配列が本当に必要なのかどうか?」を再検討する必要があります。 つまり「その配列の中身すべてが、同時にメモリ上に存在している必要があるかどうか?」を考え直さなければなりません。 もしかしたら「1回の処理で、256×256の配列が1つあれば済み、その処理を100回繰り返すだけ」で良いのかも知れません。 簡単に言えば「matrix[0][0][0]のデータと、matrix[99][255][255]のデータが、同時に必要になるかどうか?」って事です。 もし「同時に必要になるのは、matrix[0][0][0]~matrix[0][255][255]の65536個のデータだけで良い」と言うなら、3次元の配列は要りません。2次元のmatrix[SIZE][SIZE]の配列を1つだけ用意し、それを使い回しすれば良いのです。 もう一度「本当にmatrix[SLICE][SIZE][SIZE]の配列の中身すべてが、同時にメモリ上に存在している必要があるかどうか?」を考え直してみて下さい。

  • goosyu
  • ベストアンサー率58% (36/62)
回答No.3

多次元配列使うことがあまり無いのですが,NEWで確保する方法をアップしておきます。 【修正前】  signed short int matrix[SLICE][SIZE][SIZE]; 【修正後】  signed short int (*matrix)[SIZE][SIZE];  matrix = new signed short int[SLICE][SIZE][SIZE]; 使い終わったらメモリ開放「delete [] matrix;」を忘れずに。

momoharata
質問者

お礼

さっそくやってみたいと思います。的確なアドバイス頂きどうもありがとうございました。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.2

>fin.read((char*) &matrix[i][j][k],sizeof(signed short int)); このコードが何を意図しているか、説明していただけますか?

momoharata
質問者

補足

ググッて調べたので、私もきちんと理解していないのですが、バイナリファイルを読み込む時に使えるらしいので使用してみました。ただ、調べた時の記述は、 double d; while(!fin.eof()){ fin.read((char*) &d,sizeof(double)); cout<< d <<endl;} と変数が1次元の場合の記述でしたので、まねして作ってみました。 私がここでmatrix[i][j][k],と記述しているのは、三次元で処理しようとしているため、signed short intとしているのは、バイナリファイルの中身は符号付きの整数であると分かっているためです。 補足ですが、医療用のCT画像(256pixelx256pixelx100枚)バイナリ形式で保存されているデータを処理処理したくて、バイナリファイルを読み込んでる所です。 質問の答えになっていますでしょうか? よろしくお願いします。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.1

>下のように書くとエラーになってしまいます。 何をしたときに(コンパイル時?実行時?)、 どんなエラー(エラーメッセージの内容は?)が出るかを、 具体的に書いてください。 「エラーが出る」だけでは、何も答えようがありません。

momoharata
質問者

補足

実行時に問題が発生したため、CTprojection.exe を終了します。 ご不便をおかけして申しわけございません。と表示されます。 ただ、ここで定義しているSLICE値を1~4までなら上手く動作します。 これ以上SLICE値が増加するとエラーになってしまいます。 質問に対して上手く回答できていますでしょうか? 初心者なので、まだ上手く説明できなくてすみません。

関連するQ&A