2009-08-16 18 views
0

今日私はgccと奇妙な出会いがありました。配列の値が自動的に0に変更されました

float len[ELEM+1]; 
len[1]=1.0; len[2]=2.0; len[3]=3.0;         //length 

nod[1][1] = 1; 
nod[1][2] = 2; 
nod[2][1] = 2; 
nod[2][2] = 3; 
nod[3][1] = 3; 
nod[3][2] = 4;    //CONNECTIVITY 


for(i=1;i<nnod;i++) 
    for(j=1;j<nfree;j++) 
/* blah blah.........*/ 

変動:次のコードを検討

float len[ELEM+1]; 
len[1]=1.0; len[2]=2.0; len[3]=3.0;         //length 

nod[1][1] = 1; 
nod[1][2] = 2; 
nod[2][1] = 2; 
nod[2][2] = 3; 
nod[3][1] = 3; 
nod[3][2] = 4;    //CONNECTIVITY 

LEN [1] = 1.0。 len [2] = 2.0;

for(i=1;i<=nnod;i++) 
    for(j=1;j<=nfree;j++) 
/* blah blah.........*/ 

唯一の違いはbold.The問題で強調表示され、このです 長さが後に印刷される場合、最初のコード印刷がlen [1]とlen [2](および式でそれらを使用して)0.0000として2番目のコードが印刷され、これらの変数の正しい値を使用しています。

何が問題なのですか。私はまったく混乱しています.--

注:lenは他の場所では変更されません。

+3

あなたが削除した関連情報の量のためにあなたの質問は非常に不明です。この問題を示す最小限でコンパイル可能なコードサンプルを投稿して、自分自身で見ることができますか?また、CおよびC++配列インデックスではゼロから始まることに注意してください。 –

+3

問題を示す実際のコンパイル可能なコードを投稿してください。 –

+2

と仮定しないでください。 lenがあなたが思っていた値と違う値になった場合は、他のどこかで*変更されます。デバッグの最も基本的な事実の1つは、コードに関するあなたの前提が*間違っているためにバグが存在することです。そして、あなたは明らかに、バグがどこにあるか、そうでないかを伝えるためにこれらの前提を信用できません。 – jalf

答えて

8

nodの定義を表示する必要があります。あなたがメモリを上書きしているという良いチャンスがあります(0ではなく、1で配列を開始するという事実に基づいています)。例えば

、NODのように定義されている場合:

int nod[3][2]; 

可能配列の添字は0-20-1あり、ない1-31-2

nod[0][0] nod[1][0] nod[2][0] 
nod[0][1] nod[1][1] nod[2][1] 

そのケースの場合あなたは記憶がほぼ確実に上書きされているので、すべてのベットはオフになっています。他のデータを破壊する可能性があります。

をメモリに直接入力してnodにした場合、このメモリのオーバーフローによって変更理由がわかります。次の図は、これを説明しようとします(しようとします)。さんがあなたのnod定義があるとしましょう:

int nod[3][2]; 

いますが、代わりにnod[0-2][0-1]nod[1-3][1-2]を設定しよう:

 +-----------+ 
+0000 | nod[0][0] | 
     +-----------+ 
+0004 | nod[0][1] | 
     +-----------+ 
+0008 | nod[1][0] | 
     +-----------+ 
+000c | nod[1][1] | 
     +-----------+ 
+0010 | nod[2][0] | 
     +-----------+ 
+0014 | nod[2][1] | 
     +-----------+ 
+0018 | len[0] | and nod[3][0], should you be foolish enough to try :-) 
     +-----------+ 
+001c | len[1] | and nod[3][1] * 
     +-----------+ 
+0020 | len[2] | and nod[3][2] * 
     +-----------+ 

C/C++にはオーバーフロー用の定期的な配列の範囲をチェックしません。したがって、nod[3][something-or-other]を設定しようとすると、あなたの質問に似たトラブルに遭遇します。

使用しているビットパターン(3と4)印刷時にドン以来、彼らは確かに」(0.0000を与えると思いますので、それぞれIEEE754単精度4.2x10 -45と5.6x10 -45に等しいですより正確な値を与える書式文字列を使用しているように見えます)。

前に、関連するnod変数を設定した後len変数すぐに出力になり、この理論をテストする良い方法、何かのように:変数はメモリ内にレイアウトされている方法として

printf ("before: len1 = %f, len2 = %f\n", len[1], len[2]); 
nod[3][1] = 3; 
nod[3][2] = 4; 
printf ("after : len1 = %f, len2 = %f\n", len[1], len[2]); 

実際の詳細上で説明したものとは異なるかもしれないが、理論はまだ成立する。

2つの可能な解決方法が問題になる場合があります。

  • C/C++の意図するゼロベース配列を使用します。または
  • int nod[4][3]のように、異常な使用に十分なスペースをあけて定義します。
+0

合意。私はすべての宣言のために1を追加しました*(float len [ELEM + 1];)*は開始値を1とみなします。しかし、原因は#define of NODEになりました(nodはfloat nod [NODE + 1] [3])それ自体。それは意図されたものより1つ小さかった。 :(あなたの詳細な説明をありがとう:) – Akilan

0

確かにバッファの上書きがあります。境界を確認して、あなたの例では配列のサイズを指定しないので、それ以上のことは言えません。

C++を使用している場合は、配列をstd :: tr1 :: arrayまたはboost :: array(それらは同じです)で置き換えると、手がかりが得られます。

0

lenが変更されていることを確認するには、gdbのwatchpointを設定してみてください。デバッグ情報(-g)と最適化なし(-O0)でプログラムをコンパイルしてください。そして、lenの宣言の近くにブレークポイントを設定し、watch len[0]のウォッチポイントを追加して実行します。 len[0]が変更されると、gdbは壊れてしまい、新しい値と古い値が表示されます。

関連する問題