2009-08-16 171 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而第二個代碼是打印並使用這些變量的正確值。

怎麼回事?我完全困惑:-o

注意:len不會在其他地方修改。

+3

由於您刪除了大量的相關信息,因此您的問題非常不清楚。你能發佈一個最小但可編譯的代碼示例來演示這個問題,以便我們可以親眼看到它嗎?此外,你知道在C和C++數組索引從零開始,而不是一個,對吧? – 2009-08-16 13:25:36

+3

發佈一些說明問題的真實可編譯代碼。 – 2009-08-16 13:28:48

+2

並且不做假設。如果len以不同於你想象的價值結束,那麼最可能的是它在其他地方被修改。調試的最基本的事實之一是存在該錯誤,因爲您對代碼的假設是錯誤的*。所以你顯然不能相信這些假設來告訴你錯誤在哪裏或者在哪裏。 – jalf 2009-08-16 13:32:03

回答

8

您需要告訴我們關於nod的定義。有一個很好的機會(基於你開始數組1而不是0的事實),你正在覆蓋內存。

例如,如果點頭定義爲:

int nod[3][2]; 

可能的數組下標是0-20-11-31-2

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

如果的情況下,你的記憶力幾乎肯定會被覆蓋,在這種情況下,所有的投注都是關閉的。你可能會破壞其他任何數據。

如果lennod之後立即放入內存中,此內存溢出將解釋爲什麼它被更改。下圖將(試圖)說明這一點。比方說,你nod的定義是:

int nod[3][2]; 

,但你嘗試設置nod[1-3][1-2]而不是nod[0-2][0-1]

 +-----------+ 
+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)中的位模式等同於IEEE754單精度4.2×10 -45和5.6×10分別-45所以他們會肯定會給0.0000打印時(因爲你不」 t似乎正在使用格式字符串,它會給你更精確的值)。

一個很好的方式來測試這個理論將立即輸出len變量之前並設置相關nod變量後,是這樣的:變量是如何在內存佈局

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]); 

實際細節,以可能與上述不同,但理論仍然成立。

兩種可能的解決方案,如果事實證明是問題。

  • 使用零基數組作爲C/C++預期;或
  • 定義它們有足夠的空間來處理您的不常用,如int nod[4][3]
+0

同意。我爲每個聲明*添加了1(如在float len [ELEM + 1];)*中以將起始值解釋爲1.但是罪魁禍首竟然是在NODE的#define中(點頭是float nod [NODE + 1] [3])本身。這比預期的要少一個。 :(感謝您的詳細解釋:) – Akilan 2009-08-17 09:50:06

0

你肯定有一個緩衝區覆蓋。檢查你的界限,你沒有在你的例子中提供任何數組大小,這讓我們無法多說。

如果你使用C++,試着用std :: tr1 :: array或boost :: array(它們是相同的)替換你的數組,它們會給你一些線索。

0

您可以嘗試在gdb中設置watchpoint以查看len何時被修改。確保使用調試信息編譯您的程序(-g)並且不進行優化(-O0)。然後,在聲明len附近設置一個斷點,然後添加一個觀察點watch len[0],然後運行。只要len[0]被修改,gdb就會中斷,它會告訴你新的和舊的值。