• 締切済み

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

プログラミングの初心者なのですが、現在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; } } }

みんなの回答

  • chie65535
  • ベストアンサー率43% (8518/19364)
回答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でしたので、無事読むことが出来ました。 まだまだ、分からない事ばかりなので勉強になりました。 この機会に「エンディアンの違い」や「バイトオーダー」なども勉強してみたいと思います。どうもありがとうございます!

  • chie65535
  • ベストアンサー率43% (8518/19364)
回答No.6

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

  • chie65535
  • ベストアンサー率43% (8518/19364)
回答No.5

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

  • chie65535
  • ベストアンサー率43% (8518/19364)
回答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% (2126/6288)
回答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% (2126/6288)
回答No.1

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

momoharata
質問者

補足

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

関連するQ&A

  • 三次元配列の動的メモリの確保?

    const int SLICE=2; const int SIZE=256; signed short int *matrix=new signed short int[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[SLICE][SIZE][SIZE],sizeof(signed short int)); } } } delete[] data; 三次元データを読み込むために、三次元配列を使って読み込もうとしたのですが、上手く読み込めません。 三行目の所で、error C2440: '初期化中' : 'short (*)[256][256]' から 'short *' に変換できません。 七行目の所で、error C2109: 配列または、ポインタでない変数に添字が使われました。 というエラーがでます。動的メモリの確保の仕方がまずいのでしょうか? どなたか教えて頂けますでしょうか?よろしくお願いします。

  • C++画像処理に困っています。。

    #include<iostream> #include<fstream> using namespace std; int main() { char outfile[]="256x256x100.bin";     ifstream fin(outfile, ios::in| ios::binary); ofstream fout; if(!fin){ cout << "ファイル1はオープンできません。endl"; return 1; } } const int SIZE=256; const int SLICE=100; signed short int* matrix= new signed short int[(SIZE)*(SIZE)*(SLICE)]; for(int i=0; i<SIZE*SIZE*SLICE; i++){ fin.read((char*) &matrix[i],sizeof(signed short int)); cout << matrix[i]; } delete[] matrix; fin.close(); fout.close(); return 0; } 上のように256x256x100の三次元データ(XxYxZ)を読み込む事ができ、256 pixelx256 pixelの画像が100枚表示することが出来ました。 次に、その画像データをXZ軸方面から見た画像データにしたいのですが、どのようにすればいいのでしょうか? たぶんY方向のデータを足し算して平均を求めればよいとは思うのですが、 プログラミング初心者なので、処理の方法が全く思い浮かびません。 どなたか教えて頂けますでしょうか?

  • 100x100x100のファイルの読み込み方

    プログラミング全くの初心者なのですが、 100x100x100の整数で表されたファイルを読み込む場合、 #include<iostream> #include<fstream> using namespace std; int main(){ ifstream fin; fin.open("100x100x100.txt"); int matrix[100][100][100]; const int SIZE=100; for(int i=0; i<SIZE; i++){ for(int j=0; j<SIZE; j++){ for(int k=0; k<SIZE; k++){ fin>> matrix[i+1][j+1][k+1]; } } } fin.close(); return 0; } としてファイルを読み込んでいるのですが、他に良い方法はないでしょうか?最終的には、読み込んだファイルの各列ごとの平均値をとりたいと思っています。 誰かご教授お願いします。

  • 100x100行列の平均値を求めたい

    const int SIZE=100; for(int i=0; i< SIZE; i++){ for(int j=0; j< SIZE; j++){ fin >> array[i][j]; } } double sum=0.0; double ave=0.0; int J =3; for(int i=0; i< SIZE; i++){ sum += array[i][J]; } ave = sum / SIZE; cout << sum << endl; cout << ave << endl; 100x100行のファイルを読み込んで、すべての行の足し算および平均値を求めたいと思います。上のようある列(または行)を固定して求めることは出来るのですが、一度に0~99までの足し算および平均値を求めるやり方はどのようにしたらよろしいのでしょうか?たぶんfor文を使えば、できるのかなとは思うのですが、なかなか思うように行きません。 アドバイスよろしくお願いいたします。

  • メモリ領域の確保の仕方

    あまりうまく書けなかったのですがよろしくお願いします。 ファイルから二次配列を読み込むプログラムを作ろうとしました。 /*****行列Aに値を入れる********/ for(i = 0; i < Qap->iN; i++){ for(j = 0; j < Qap->iN; j++){ fscanf(fp, "%d", &Qap->matrixA[i][j]); } } /*****行列Bに値を入れる********/ for(i = 0; i < Qap->iN; i++){ for(j = 0; j < Qap->iN; j++){ fscanf(fp, "%d", &Qap->matrixB[i][j]); } } のように書くために、二次配列の領域を確保しようとしたとき、 #define SIZE 100 //行列のサイズ typedef struct hairetu{ int iN; int matrixA[SIZE][SIZE]; int matrixB[SIZE][SIZE]; }hairetu; としてmatrixA[SIZE][SIZE]のようにした場合は Qap = malloc(sizeof(hairetu));//hairetu分の大きさの領域を確保 とすれば領域を確保できたのですが、 typedef struct hairetu{ int iN; int **matrixA; int **matrixB; }hairetu; のように二次配列を**matrixAと表そうとして、 fscanf(fp, "%d", &Qap->iN); のようにファイルから行列のサイズを読み込もうとした場合、 Qap = malloc(sizeof(hairetu));//hairetu分の大きさの領域を確保 とやってもコンパイルはできるのですがアプリケーションエラーが出てしまいます。 何故だかよくわかりません。 二次配列を**matrixAのように表そうとした場合の領域確保の仕方を教えて下さい。 わかりづらくて本当に申し訳ありませんがお願いします。

  • C++ 動的確保について

    学校の演習課題で「クラス Array のメンバ変数を以下のように変更して,配列のサイズを実行時に決められるようにしたい.コンストラクタを適切に修正しなさい.配列のサイズはコンストラクタの引数で指定できるようにすること.main 関数内のオブジェクトの宣言部分を適当に変更して動作を確認しなさい.」という課題が出ました。 指示のメンバ変数の変更は、sizeを定数にしていたものを変数にし、arrayを配列からポインタにする点です。 もとのプログラムはI、私がいじったものがIIです。どうにもセグメンテーションフォルトから抜け出せなくて困っています。どのようにしたら題意のプログラムになるのでしょうか? よろしくお願いします。 ここからI~ #include <iostream> using namespace std; class Array{ private: const static int size = 6; int array[size]; public: Array( ); int getSize( ); void put( int index, int data ); int get( int index ); void show( ); }; Array::Array( ) { for ( int i = 0; i < size; i++ ) { array[i] = 0; } } int Array::getSize( ) { return size; } void Array::put( int index, int data ) { array[index] = data; } int Array::get( int index ) { return array[index]; } void Array::show( ) { cout << "| "; for ( int i = 0; i < getSize( ); i++ ) { cout << get(i) << " | "; } cout << endl; } int main( ) { Array array1; array1.put(1, 2); array1.put(4, 1); array1.show( ); return 0; } ~ここまでI ここからII~ #include <iostream> using namespace std; class Array{ private: int size; int *array; public: Array(int s); ~Array(); int getSize(); void put(int index, int data); int get(int index); void show(); }; Array::Array(int s) { size = s; array = new int; for (int i = 0; i < size; i++) { *array = 0; array++; } array -= size; } Array::~Array() { delete[] array; cout << "デストラクタが呼ばれました。配列の要素数分のメモリを開放します." << endl; } int Array::getSize() { return size; } void Array::put(int index, int data) { *(array + index) = data; } int Array::get(int index) { return *(array + index); } void Array::show() { cout << endl << "| "; for (int i = 0; i < getSize(); i++) { cout << get(i) << " | "; } cout << endl; } int main() { int s = 0; cout << "確保するサイズを入力してください:"; cin >> s; Array array1(s); array1.put(1, 2); array1.put(4, 1); array1.show(); return 0; } ~ここまでII

  • c++ で *の逆三角旗を作りたいです

    普通の三角旗はできましたが逆三角旗が分かりません 例えば3と入力したら * ** *** ** * こんな感じで出力させたいのですが考え方が分かりません 普通の方のコードはこんな感じです int i, j; cin>>num; for (i = 1;i <= num;++i) { for (j=1;j<=i;j++) { cout << "*"; } cout << endl; } for (i = 1;i <= num-1 ;i++) { for (j=1;j<=num-i;j++) { cout << "*"; } cout << endl; } cout << endl;

  • C++の無限ループを解決してください

    アルゴリズムを勉強するときに以下のソースを書きました; void weighted_quick_union_algorithm() { static const int volume = 10; enum status { terminate_, union_, find_ }; string str; status sta; vector<int> system(volume, 0); vector<int> size(volume, 1); for (int index = 0; index != volume; ++index) { system[index] = index; } do { cout<<"cin"<<endl; cin >> str; for (string::size_type index = 0; index != str.size(); ++index) str[index] = toupper(str[index]); if (str == "UNION") sta = union_; else if (str == "FIND") sta = find_; else if (str == "TERMINATE") sta = terminate_; switch (sta) { case(0): { cout << str << endl; break; } case(1): { cout << str << sta << endl; int p(0), q(0), i(0), j(0); while (cin >> p) { cin >> q; for (i = p; i != system[i]; i = system[i]); for (j = q; j != system[j]; j = system[j]); if (i == j) continue; if (size[i] < size[j]) { system[i] = j; size[j] += size[i]; } else { system[j] = i; size[i] += size[j]; } cout << p << " - " << q << endl; } cout<<"break"<<endl; break; } case(2): { cout << str << sta << endl; break; } } } while (sta); } しかし unionを入力しあと ; でwhile(cin>>p)をブレイクしたら cin break UNION1 cin break Union1 で無限ループ 結構時間かかったが間違いがわかりません ちなみに最少は while(cin>>p>>q)と書いていましたが同じ結果です。 どうかお願いします

  • C++ ソートのやり方

    僕が作ったプログラムで、これはバブルソートなのかわからないので教えてください。 また、ほかのソートの仕方も教えてください。 よろしくお願いします。 汎用関数を使っているのでわかりにくいかもしれないですがお願いします。 #include <iostream> using namespace std; template <class X>void Sort(X *data, int size) { X temp; for (int i = 0; i < size; i++){ for (int j = i + 1; j < size; j++){ if (data[i]>data[j]){ temp = data[i]; data[i] = data[j]; data[j] = temp; } } } } int main() { int i[10]{1, 4, 3, 5, 2, 10, 2, 7, 6, 8}; char c[10]{'c', 'b', 'z', 'a', 'x', 'y', 'j', 'n', 'm', 'r'}; Sort(c, 10); Sort(i, 10); for (int j = 0; j < 10; j++){ cout << i[j] << ' '; } cout << endl; for (int j = 0; j < 10; j++){ cout << c[j] << ' '; } cout << endl; getchar(); return 0; }

  • このプログラムの問題点を教えてください。

    //数独 #include <iostream.h> const int num_Max = 100; //一辺のマス最高値 void input_data( int a, int [num_Max][num_Max] ); //入力関数 void yoko_data( int a, const int [100][100], int & ); //判定 void tate_data( int a, const int [100][100], int & ); void block_data( int a, int b, const int [100][100], int & ); main() { int num; //一辺のマスの数 int m; //一ブロックの一辺にあるマスの数 int okey; //numが正常か判別 int dx, dy, dz; int masu[num_Max][num_Max]; //全部のマス cout << "\n埋められた数独が正しいかどうか判断するプログラムです。\n"; while(1){ cout << "横何マスありますか? (4-100)>>" ; cin >> num ; if( num > num_Max || num < 4){ cout <<"範囲外です。再入力して下さい。" ; }else{ m = sqrt( num ); okey = num - m * m; if(okey != 0) cout << "その数字は数独として成り立ちません。再入力して下さい。"; } } //マスの入力 input_data( num, masu ); //横判定 yoko_data( num, masu, dx ); if(dx = 0){ //縦判定 tate_data( num, masu, dy ); if(dy = 0){ //マス判定 block_data( num, m, masu, dz ); } } if(dx == dy == dz == 0) cout <<"\n大正解♪ おめでっとー。\n"; return 0; } //入力 void input_data( int kazu, const int matrix[num_Max][num_Max]) { cout <<"\nマスの数字の入力を左上から順に、右へと行って下さい。"; for(int i = 0; i < kazu; i++){ for(int j = 0; j < kazu; j++){ cout << i+1 << "行目の" << j+1 << "列目 >>"; cin >> matrix[i][j] ; } } } //横列(行)を順に判定 void yoko_hantei( int kazu, int matrix[num_Max][num_Max]) { int kaburi; //かぶっているか判定する用 int vx = 0; //かぶっていたと判定されたかどうかを見る用 for(int i = 0; i < kazu; i++){ //横一列取り出しました。 for(int j = 0; j < kazu; j++){ for( int k = 1; j+k < kazu; k++){ kaburi = matrix[i][j] - matrix[i][j+k]; if(kaburi == 0){ //かぶってたらループから抜け出す vx++; break; } } } } if(vx > 0) cout << "\n横列(行)検索時に不適切な部分を発見しました。\n"; return vx; } //縦列(列)を順に判定 void tate_hantei( int kazu, int matrix[num_Max][num_Max]) { int kaburi; //かぶっているか判定する用 int vy = 0; //かぶっていたと判定されたかどうかを見る用 for(int j = 0; j < kazu; j++){ //縦一列取り出しました。 for(int i = 0; i < kazu; i++){ for( int k = 1; k < kazu-1; k++){ kaburi = matrix[i][j] - matrix[i+k][j]; if(kaburi == 0){ //かぶってたらループから抜け出す vy++; break; } } } } if(vy > 0) cout << "\n縦列(列)検索時に不適切な部分を発見しました。\n"; return vy; } //1ブロックごとに判定 void block_data( int kazu, int ruto, int matrix[num_Max][num_Max]) { int hantei[num_Max][num_Max] ; //判定する部分を切り出す用 int kaburi; int vz; //まずブロックごとに切り出してみる for(int i = 0; i < ruto-1; i++){ for(int j = 0; j < ruto-1; j++){ int h = 0; //何ブロック目か int g = 0; //そのブロックの何個目か (h-1)++; for(int l = 0; l < ruto-1; l++){ for(int k = 0; k < ruto-1; k++){ hantei[h][g++] = matrix[i * m + k][j * m + l]; } } } } //かぶっているか判定する for(int x = 0; x < kazu; x++){ for(int y = 0; y < kazu; y++){ for( int z = 1; z < kazu-1; z++){ kaburi = hantei[x][y] - matrix[x+z][y]; if(kaburi == 0){ //かぶってたらループから抜け出す vz++; break; } } } } return vz; } C++で作成したものです。 コンパイルエラーが出てしまうのですが、原因を教えていただけませんか?

専門家に質問してみよう