• 締切済み

メモリ破壊で困っています。

学生です。 現在、cの課題プログラムを作成していて、メモリ破壊と思われる現象で困っています。具体的には、 mallocである構造体へのポインタの3次元配列を確保したはずのものが(malloc時にNULLは返ってきていない)、その後、関係のない関数を呼んだ瞬間にその配列の値が書き換えられている。もしくはアクセスできなくなるといった状況です。 gdbで調べてみたところメモリを確保してから破壊されるまでにfreeはしていません。「関数を呼んだ瞬間に」値が変わるというのは原因がまったくわかりません。 どなたか心当たりある方、ぜひともアドバイスをよろしくお願いします。

みんなの回答

  • Werner
  • ベストアンサー率53% (395/735)
回答No.5

Hoge array[3][size1][size2]; みたいな3次元配列が欲しいけど、 size1とsize2は可変ということでしょうか。 3重ポインタ(Hoge ***array)を使って、 array[x][y][z]のようなアクセスを可能にするには以下のようにします。 ------------------------------------------------------------ Hoge ***array; /* Hoge **array[3]; とすれば最初のmallocは要らない */ /* Hoge**型 3個分の領域を確保 */ /* これでarray[0]~array[2]までが使用可能になる */ array = (Hoge ***)malloc(sizeof(Hoge **) * 3); for(i = 0; i < 3; i++) {   /* Hoge*型 size1個分の領域を確保 */   /* これでarray[i][0]~array[i][size1-1]までが使用可能になる */   array[i] = (Hoge **)malloc(sizeof(Hoge *) * size1);   for(j = 0; j < size1; j++) {     /* Hoge型 size2個分の領域を確保 */     /* これでarray[i][j][0]~array[i][j][size2-1]までが使用可能になる */     array[i][j] = (Hoge *)malloc(sizeof(Hoge) * size2);   } }   ------------------------------------------------------------ これで  Hoge array[3][size1][size2]; としたのと近い感覚でarrayを使えますが、 ポインタを経由してアクセスしている点で 単純な3次元配列(配列の配列の配列)とは異なると言うことは理解しておいてください。 (例えば、array[0][1][0]とarray[0][0][size2]が等価かどうかなどが違う。) http://florida.mes.titech.ac.jp/inf/inf-8.html この辺りがよく分からないなら、 ANo.2のサンプル2のように1次元配列で扱った方が分かりやすいし確実だと思います。 forループをなくせるし、ポインタを格納する領域も少なくてすむし。 なお > Hoge ***array[3]; だと、「"Hoge型へのポインタへのポインタへのポインタ"の要素数3の配列」 となりarray[0]~array[2]がそれぞれHoge型への3重ポインタになります。 ANo.2へのお礼のようなコードだと  array[0] は "Hoge型へのポインタへのポインタへのポインタ" 型  array[0][0] は "Hoge型へのポインタへのポインタ" 型  array[0][0][0] は "Hoge型へのポインタ" 型 となり、array[0][0][0]ではまだポインタであってHoge型では有りません。 array[0][0][0][0]や*array[0][0][0]としてやっとHoge型になります。 大まかには  Hoge array[3][size1][size2][1]; としたのと似たような状態です。 > ANo.2 > (Hoge (*)[3][10])malloc(sizeof(Hoge) * max * 3 * 10) 書き方が違うだけですが、Hoge[3][10]型max個という意味を考えて  (Hoge (*)[3][10])malloc(sizeof(Hoge[3][10]) * max) の方が私は好きですね。 # 余談 > 3次元配列のポインタは『static unsigned char (*In)[ysize][xsize];』と宣言しますよ。 3次元配列のポインタと言われると、 3次元配列へのポインタ(char (*)[size][size1][size2])の方が頭に浮かんでしまいました。 配列を扱うときは"先頭要素"へのポインタを実質配列として扱うので  3次元配列は「2次元配列の配列」だから、3次元配列の要素は2次元配列。  なので2次元配列へのポインタを「3次元配列の先頭要素を指すポインタ」と見なして3次元配列と同様に使える。 となるわけで、言葉の意図は分かるんですけどね^^;

すると、全ての回答が全文表示されます。
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.4

★昨日の夜ちょっと見ました。 ・ソース部分がないので補足欄を待っていました。 ・予想通り『3次元配列のポインタ』が正しく宣言されていませんね。 ・過去に似たような質問がありました。下の『参考URL』をどうぞ。→『3次元配列でのポインタ』回答者 No.2 です。 ・それで3次元配列のポインタの宣言方法ですが、  『Hoge ***array;』というポインタに3重に『malloc』関数で確保していますが、正しくは  『Hoge (*array)[size1][size2];』というポインタを宣言します。 ・ただし、『size1』、『size2』が固定の場合ですよ。→今回は実行時に要素数が変化するので使えませんが…。 ●サンプル1(要素数が固定の場合の3次元配列) Hoge (*array)[3][10]; ←array[max][3][10]の3次元のとき if ( (array = (Hoge (*)[3][10])malloc(sizeof(Hoge) * max * 3 * 10)) != NULL ){  // 実際の処理  free( array ); } else{  // メモリ不足 } ●サンプル2(要素数が可変の場合の3次元配列) Hoge *array; ←可変なので1次元配列として宣言(処理) if ( (array = (Hoge *)malloc(sizeof(Hoge) * max * size1 * size2)) != NULL ){  // 実際の処理  // array[max][size1][size2] のとき、array[a][b][c]とアクセスするならば  // array[(size1 * size2 * a) + (size2 * b) + c]で参照・代入可能です。  // ※なお、マクロ関数を定義してアクセルした方がスマートです。  free( array ); } else{  // メモリ不足 } ●サンプル3(複数の決まった要素数の3次元配列) union HogeArray { // 共用体  Hoge (*a0); // 1次元配列(確保時に使う)  Hoge (*a1)[3][10];  // array[max][3][10]のとき  Hoge (*a2)[5][20];  // array[max][5][20]のとき  Hoge (*a3)[8][50];  // array[max][8][50]のとき } array; if ( (array.a0 = (Hoge *)malloc(sizeof(Hoge) * max * size1 * size2)) != NULL ){  // 実際の処理  // size1=3, size2=10 のとき、array.a1[max][y][x] で参照・代入  // size1=5, size2=20 のとき、array.a2[max][y][x] で参照・代入  // size1=8, size2=50 のとき、array.a3[max][y][x] で参照・代入  // ※サンプル2のように複雑な計算はしなくてよいので扱いやすい。  free( array.a0 ); } else{  // メモリ不足 } 最後に: ・解説がほとんどないので分からないときはもう一度補足などして下さい。 ・以上。おわり。

参考URL:
http://oshiete1.goo.ne.jp/qa2619388.html
すると、全ての回答が全文表示されます。
  • ddnp009
  • ベストアンサー率25% (15/58)
回答No.3

ポインタが4byteで示される、よくある一般的な環境だとして。 > array = (Hoge ***)malloc(sizeof(Hoge **)* 3); こりゃ結局12バイトでしょ。 > array[0][i] = (Hoge**)malloc(sizeof(Hoge*) * size2); こりゃ結局 4 * size2バイトでしょ。 struct Hogeのサイズが正しく求まるのは、唯一 > array[0][i][j] = (Hoge*)malloc(sizeof(Hoge)); ここだけだわな。 C言語で配列の配列(の配列・・・)が どういったモノか、復習してください。 こんなややっこしい事しなくとも Hoge*** array = (Hoge ***)malloc(sizeof(Hoge) * (3 * size1 * size2)); でいいんじゃない?たぶん。試してないけど。 size1, size2が実行時に変化して、それをarrayのサイズに反映するとしたら、 結局全ての要素をアロケートし直さなくちゃいけない。

すると、全ての回答が全文表示されます。
  • ultraCS
  • ベストアンサー率44% (3956/8947)
回答No.2

malloc時に確保するサイズはどうなっていますか、三次元配列の最大サイズより小さくなっていると思います。 あるいは、配列に対するsizeofで確保しているとか。この場合は、ポインタのサイズにしかなりません。コレガ通用するのはstatic配列の場合だけじゃないかな。

diofhaodiu
質問者

お礼

ultraOSさん すいません、間違えましたというか補足です。プログラム中の3とか10という数字は実際にはsize1、size2という変数で実行時にわかるものです。以下のコードが正しいです。 Hoge ***array[3]; /*Hogeは自分で定義した構造体 3は静的にわかる*/ array[0] = (Hoge ***)malloc(sizeof(Hoge **) * size1); for(i = 0; i < size1; i++) { array[0][i] = (Hoge **)malloc(sizeof(Hoge *) * size2); for(j = 0; j < size2; j++) { array[0][i][j] = (Hoge *)malloc(sizeof(Hoge)); } } です。array[1]とarray[2]についても同様にしています。よろしくおねがいします。

diofhaodiu
質問者

補足

ultraOSさん ありがとうございます。 mallocは下のように行っています。 Hoge ***array; /*Hogeは自分で定義した構造体*/ array = (Hoge ***)malloc(sizeof(Hoge **)* 3); for(i = 0; i < 3; i++) { array[i] = (Hoge **)malloc(sizeof(Hoge *) * 10); for(j = 0; j < 10; j++) { array[i][j] = (Hoge *)malloc(sizeof(Hoge)); /*ここは実際には関数呼び出しを用いています*/ } } malloc時のNULLチェックなどは省略して書きました。以上のように書いているのですが、問題あるでしょうか?とりあえず、確保サイズを単純に大きくして試してみたいと思います。

すると、全ての回答が全文表示されます。
  • koedame
  • ベストアンサー率33% (10/30)
回答No.1

私も、そんなに詳しくはないのですが、 出来ればそのあたりのエラー箇所の範囲を 自分で頑張ってしぼって、そして、 その部分のソースを公開してください。 この文章だけではどうも判断材料が足りないのです。 よろしくです。

diofhaodiu
質問者

補足

koedameさん ありがとうございます。実際に値が書き変わっている箇所は、関数を呼んだだけ(gdbではsでステップ実行しただけ)で値が変わってしまっています。その関数に引数としても渡していません。 問題の3次元構造体配列のmallocの仕方は上に書かせていただいたとおりなんですが・・・。ご意見よろしくおねがいいたします。

すると、全ての回答が全文表示されます。

関連するQ&A