• 締切済み

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

学生です。 現在、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

  • アドレス格納のための二次元配列のメモリ動的確保

    アドレス格納のための二次元配列のメモリ動的確保 二次元配列のためにメモリを動的確保しなければならないのですが、 その配列に格納したいものが 「DATA型のポインタ」です。(DATA型はtypedefした構造体です。) プログラム実行中にmallocで確保した、数あるDATA型の構造体の、その先頭アドレスを リストアップするための配列です。 この場合、どのような形でmallocすればよいのでしょうか? 教えていただけるとありがたいです。よろしくお願いいたします。 -- たとえば m×n のint型の配列は、 ◆ int *i; ◆ i = (int *)malloc( m * n * sizeof(int) ); となりますよね。 この要領がでやるのが一般的にわかりやすいものだとするならその方法でやりたい (後発の人が自分のソースコードを読む可能性があるため)のです。 -- 同様にm×nの「DATA型のポインタを格納するための二次元配列」を動的確保したい場合、 ◆ DATA *d; ◆ d = (DATA *)malloc( m * n * sizeof(DATA) ); この文にどのように付け加えたら良いのでしょう? もうあと一歩な気がするのですが(笑)。しかし参考書等で勉強しましたがわかりませんでした・・・。 わかる方、どなたかよろしくお願いいたしますm(_ _)m あとこれだけ通ればコンパイルが通るんです!!!!! たぶん(笑)

  • 配列ポインタの関数中のメモリ領域

    C初心者です。 関数中で配列ポインタを宣言する場合についての質問です。 たとえばDouble型の2次元のローカルな配列ポインタを用いる場合、 その配列要素数が100である場合は void 関数名(引数1,引数2,...){ int i; double *a[2]; for(i=0;i<2;i++){ a[i] = (double*)malloc(100*sizeof(double)); } for(i=0;i<2;i++){ free(a[i]); } } またこの値を引数1とする場合、引数1をoutとすると void 関数名(double *out,....) とし、 for(i=0;i<2;i++){ out[i] = a[i]; } とすればよいのでしょうか? もしこれがあっているとすると、つぎのような現象で困っています。 配列要素数を50000個ぐらいとし、複数の関数で、同様に mallocを用いて、配列ポインタのローカルでメモリ領域を確保しようとした場合、コンパイルは成功するのですが、その後実行すると、エラーが発生したというメッセージとともにコマンドウィンドが強制終了します。 コンパイラはVisual C++ EXpress Edition 2008です。 データサイズを小さくすると、エラーは起きません。 malloc関数で確保するメモリサイズは、関数の入力引数で定義された変数を用いて計算しており、データサイズに応じて変更されます。 よろしくお願いいたします。

  • c言語のmalloc関数、またrealloc関数

    c言語のmalloc関数は確保するメモリの領域を、配列としてのみしか処理出来ないのですか。 つまり、malloc関数で確保したメモリの領域を変数、また多次元配列、また構造体としては処理出来ないのでしょうか。 c言語のrealloc関数は以前の確保したメモリの領域から、確保し直したメモリの領域の場所が変わるかもしれないという事ですが、この場合の場所が変わるという意味は、メモリの領域のアドレスが変わるという事でしょうか。 また、以前の確保したメモリの領域に代入していたデータが使用出来なくなるという事でしょうか。

  • メモリのセグメント違反の解決方法を教えてください。

    こんにちわ, 現在プログラムを作成しているのですが,Segmentation Faultが出て困っています。 そのセグメント違反が出ているのがmallocの中(PCインナーの関数)で普通ならmallocの返り値がNULLかそれ以外かということになりますが,それ自体も中でセグメント違反が起こるので帰ってきません。 MALLOC_CHECK_=1によってその触っているポインターを見ると, free(): invalid pointer 0x93c5380! free(): invalid pointer 0x93c5c18! とでるので,おそらくmallocのなかで必要なくなったポインターをフリーをしていると考えられるのですが, gdbのwatchpointでそのアドレスを指定してみてみると,メインに入る前にそのポインタ自体をいじっている関数も内部的な関数みたいでどこをなおすとセグメント違反が直るのかわかりません。 このようなメモリ問題がおきたときどのようなツールや解決法があるのでしょうか。 よろしくお願いします。

  • C言語のメモリ領域確保

    ポインタ変数ををmain関数で宣言し、関数test()にて必要分だけ領域確保してそのアドレスをmain関数のポインタ変数に渡して利用することは可能でしょうか。 (サイズのわからないテキストデータを、十分に大きな配列に入れるのではなく、関数でメモリを動的確保して無駄の無い配列に入れたい等) C言語ではやはり無理で、構造体のリストにするのが一番でしょうか。 初歩的なことで申し訳ありませんがどなたかお願いいたします。

  • malloc関数によるメモリの確保

    C初心者です。 malloc関数によるメモリの確保に関して教えてください。 2次元配列のサイズに対してmalloc関数の引数値をたとえば、 (double*)malloc(datasize*sizeof(double)) などとしメモリ領域を確保すると、メモリアドレスはデータのサイズ によらず一定 1234044、1234048となります。 データサイズを大きくし、datasize*sizeof(double)が16Kバイトを超えるとcmd.exeがエラーとなり落ちます。 デバックモードで実行すると 「"System.AccessViolationException"のハンドルされていない例外が不明なモジュールです。で発生しました。 追加情報:保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリがこわれていることが考えられます」 というメッセージがでます。 コンパイラはExpressEdition2008です。 この現象を回避するにはどうすべきか、なぜこのようなことが起こるのかご教授ください。 よろしくお願いいたします。

  • 動的なメモリ領域の確保

    double型変数5個分のメモリをmalloc関数により確保し,その確保した要素のアドレスを表示するように,プログラムを作る問題で、 (注)に「 %pで表示するためには,double型へのポインタ(double *)をvoid型へのポインタ(void *)にキャストする必要がある.」と書かれていたのですが、どういうことでしょうか? 以下のようでいいのでしょうか? #include<stdio.h> #include<stdlib.h> #define COUNT 5           // 動的に確保するメモリ領域数を示すマクロ定数の定義 int main(void) {  // 動的に確保するメモリ領域のアドレスを保持するポインタ変数の宣言  double * pointer;  int i;                  // for文で使用する変数の宣言  // int型変数5個分のメモリ領域を確保  pointer = (double *)malloc(sizeof(double) * COUNT);  if(pointer == NULL) {        // メモリ領域の確保が失敗した場合   printf("メモリ領域を確保できませんでした.\n");   exit(1);                // プログラムの終了  }  for(i = 0; i < COUNT; i++)   printf("%d番目のアドレスは%pです.\n", i + 1, pointer + i);  free(pointer);            // 確保したメモリ領域の解放  return 0; }

  • 関数にポインタを渡して動的確保する時について

    どうにも動的確保について間違っている気がするのでお尋ねいたします。 よくメモリを動的に確保する場合に私は次のようなプログラムを書きます ポインタを用意する(例えばint *p) mallocでメモリ確保 ポインタを関数に渡す(Func(p)) 関数側でreallocし、値を代入する(p=(int *)realloc(p,sizeof(int)*num)) 関数呼び出し側で、その値を使う しかし、この方法を使うとどうにも関数を呼び出した際のポインタ(p)と、reallocした後のポインタ(p)の値が違うことがあり、値が不定になることがあります。 (reallocのメモリの確保の仕方のせいでしょうか) この使い方は恐らくどこか間違っていると思うんですが、いまいち納得のいく解決策が思いつきません。 例えばポインタを引数ではなく戻り値として得ればできますが、2つ以上のポインタについてはできません。 何卒ご教授のほどをよろしくお願いいたします。

  • ファイルから構造体へデータを格納(動的メモリ割り当て)

    C言語の勉強をしいております。 typedef struct address { char names[32]; /* 名前 */ char tels[32]; /* 電話番号 */ struct address *prev; /* 前のリスト */ struct address *next; /* 次のリスト */ }Address; という構造体へ、ファイルから読み込んだテキストデータ(名前と電話番号がTABで区切られている)を格納したいのですが、配列ではなく、動的にメモリを確保しながら格納する方法を教えていただけないでしょうか? 処理の流れとしては、 ・1つめの構造体の*prevにはnullを入れておく。 ・1つめの構造体へファイルの1件目のデータを格納する。 ・ファイルのデータがまだある場合には、malloc関数を使ってメモリを確保し、malloc関数からの戻り値を1つめの構造体の*nextへ格納する。 ・構造体へ2件目のデータを格納する。 このような感じだろうという程度しか分からず、ソースも書けずにいます・・・。 配列を使用したサンプルはあるんですが、動的に処理を行う方法を教えていただけないでしょうか? よろしくお願いいたします。

  • ポインタについての良いテキストを探しています。

    ポインタ完全制覇、秘伝問答ポインタ編は読了しました。 しかし、ダブルポインタ(便宜上こう書きますが、ポインタのポインタのことです)や トリプルポインタが出てくると、いきなり分からなくなってしまいます。 アドレスと値の関係を図解してみても、なぜこんな風にする必要があるのだろう?その必然性は? となってしまい、本質的な理解ができていないと感じています。 関数に渡すときの値渡しと参照渡しについては理解できているつもりです。 ですが、それに、構造体や、構造体のメンバーに文字列がある場合、mallocなどが関わってくると ゴチャゴチャになっていきなり分からなくなってしまいます。 上記の本は、文字列と配列とポインタあたりは解説してあり、そのあたりは理解しているつもりなのですが、ダブルポインタやトリプルポインタについては明確な記載がありません。 以前の質問で、 http://okwave.jp/qa/q6478987.html >3次元の構造を持つなら 3次元配列が必要であり, それを動的に確保しようとしたら「ポインタのポインタのポインタ」は自然な発想だと思う. とご回答を頂いたことがあるのですが、"自然に"だけでなくじっくり考えても理解できていません。 その他のご回答もなぜそのような状況でそのようなポインタの使い方が必要になるのかなど理解出来ないところが多いです。 基礎が大事だというのは十分理解しているつもりですが、 基礎だけでなく、その上のレベルでのポインタの解説や勉強に役立つテキストを教えてください。 なにとぞよろしくお願いいたします。 また、所要のため土日はネットに繋ぐことができませんのでお返事が遅れることをご了承ください。

専門家に質問してみよう