- 締切済み
変数に入れた情報が記憶されていない
CygwinでC言語プログラミングを行っています。 正規乱数を使って地形を生成し、島の個数を島の周長ごとの統計データにしたいのですが、なぜか島の周長を表す変数ConSize[島に割り振った番号x]が途中から0になってしまいます。 プログラムの流れとしては 1.島を生成 ↓ 2.島の周長を数えて、変数ConSize[島に割り振った番号x]に、番号xの島の周長を記憶 ↓ 3.ConSize[x]の島がいくつあるかを for( i=1; i<=consize_max; i++ ){ N_con[i] = 0; } for( k=0; k<=cont_max; k++ ){ N_con[ConSize[k]]++; } で集計しています。 consize_maxは島の周長で最大のもの cont_maxは島の数 ConSize[k]は、島番号kの島の周長 N_conはある周長を持つ島の数です 2の段階では、ConSizeの値はちゃんと得られていたのに、3を実行した後にprintfしてみると、なぜかConSizeの値が全て0になってしまっています。 なので3の段階に何かしら問題があるのだと思い、3だけプログラムを載せておきます。 なぜ、一度記憶した変数内の情報が消えるのか、アドバイスお願いします。
- みんなの回答 (4)
- 専門家の回答
みんなの回答
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
No.1 です。 配列の境界を越えたアクセスが発生した場合、多くのC言語の処理系では、何もなかったかのように実行されます。 Cの規約上、たとえば、N_con[i] は、単純に N_con の先頭から、i 個分離れた位置にあるものをポイントします。それが、たまたま次の変数や配列だと、何の断りもなく破壊されます。 さすがに、すべてのデータ領域を超えれば、OSがトラップしてくれますが、次の変数を壊したくらいでは何も起こりません(内部的には大変ですが) これが、よく言われる、「バッファオーバーフローによる脆弱性」につながっているわけですが。 さて、この場合、N_con[] のサイズも、consize_max もおわかりのはずなので、チェックはできると思いますが。 一般的にいえば、consize_max の上限チェックが行われていないので、コードとしては危険なコードになります。 追加で提示されたコードにも、肝心の、N_con[] に関する情報がないので、(あと、consize_max を決定する l (を決定する Size1) の大きさもわからないので)やはり、不安ではあります。 for( i=1; i<=consize_max; i++ ){ N_con[i] = 0; } の直後で、ConSize[] をチェックしてみるのも手かもしれません。 いずれにしても、変数がおかしくなったというのであれば、チェックする範囲を縮めて、どの瞬間におかしくなるかをチェックするのは、よくやる手です。
> 3の段階に何かしら問題がある 必ずしもそうだといいきれない場合がありますので、 ソースコードを全部見せてくださる方がよいと思います。
お礼
miki1459さん ご返答ありがとうございます。了解しました。 for( k=1; k<=Size2-1; k++ ){ for( l=0; l<=Size1-1; l++ ){ con_x[k][l] = -1; con_y[k][l] = -1; } } consize_max = 0; m=0; for( k=1; k<=p_max; k++ ){ l=0; pass=0; for( i=1; i<=n-1; i++ ){ for( j=1; j<=n-1; j++ ){ if( p[i][j] == k ){ if( p[i][j-1] == -2 ){ X0 = j; Z0 = p[i][j]; X1 = j-1; Z1 = p[i][j-1]; con_x[m][l] = i; con_y[m][l] = Contour(n); l++; pass=1; } if( p[i][j+1] == -2 ){ X0 = j; Z0 = p[i][j]; X1 = j+1; Z1 = p[i][j+1]; con_x[m][l] = i; con_y[m][l] = Contour(n); l++; pass=1; } if( p[i-1][j] == -2 ){ X0 = i; Z0 = p[i][j]; X1 = i-1; Z1 = p[i-1][j]; con_x[m][l] = Contour(n); con_y[m][l] = j; l++; pass=1; } if( p[i+1][j] == -2 ){ X0 = i; Z0 = p[i][j]; X1 = i+1; Z1 = p[i+1][j]; con_x[m][l] = Contour(n); con_y[m][l] = j; l++; pass=1; } } } } if( pass ) { ConSize[m] = l; if( ConSize[m] > consize_max ){ consize_max = ConSize[m]; } m++; } } cont_max = m-1; /* cont_max = max number of con_x,y */ /*--- Number of Contours which are same size; N_con[] ---*/ for( i=1; i<=consize_max; i++ ){ N_con[i] = 0; } for( k=0; k<=cont_max; k++ ){ N_con[ConSize[k]]++; }
補足
「回答のお礼」に記したコードの補足ですが―コードが長すぎるので、フラクタルを利用した地形生成は省いた、部分的なコードを記します。 cont[][0]は海岸線(海抜=0のポイント)のx座標 cont[][1]は海岸線のy座標を表します。 P[][]という値について p=-1が陸地 p=-2が海 を表し(Pは島の独立性の認識に必要) z[][]はフラクタルを使って作った地形の各座標の高度です。 今、cont[][]はgnuplot的に等高線(海抜0)を描くために、z=0となるx座標、y座標を関数contour()で一次関数的に計算しています。X,Y,Z0は関数contour()に必要な値です。 要するに、cont[][]は島の海岸線上の座標を表したものです。 一つにの独立した島の海岸線(周)に属するcont[][]の数を数え、それをcontour[][]にカウントしています。 分かりにくくてすみませんが、変数の説明はこんな具合です。
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
No.1 訂正です。 > などと定義されいてて、consize_max が、N_con を大幅に超えていて、 …… などと定義されいて、consize_max が、実は、N_con[] の要素数を大幅に超えていて、 ですね。
お礼
AsanoNagiさん 御返答感謝します。 僕もそれを考えたのですが、配列に対して要素数が大幅に超えた場合、core dumpになると思うのです。 coreを吐かずに数値エラーを伴って無理やり実行されてしまう場合もあるのでしょうか? よろしくお願いします。
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
全体の処理がわからないとはっきりしたことは言えません。 ひとつ可能性とした考えられるのは、 int N_con[10]; int ConSize[1000]; などと定義されいてて、consize_max が、N_con を大幅に超えていて、N_con[] の初期化時に0で上書きされたかなとは思えます。 あと、2.の ConSize[] と 3.の ConSize[] が、スコープの関係で実は別物だったとか。
お礼
ご丁寧な返答ありがとうございます。 ご指摘のとおりでした。 配列データを丁寧に見直したところ、要素数が大幅にオーバーしていました。上書きが行われていた事がわかりました。 Size1をSize2にして実行してところ、問題は解決されました。 ありがとうございました!