2010-04-30 33 views
2

我對C比較陌生,現在這讓我感到困惑。它是一個更大的程序的一部分,但我寫了這個小程序來描述我遇到的問題。爲變量賦值會被存儲在錯誤的地方嗎?

#include <stdio.h> 

int main() 
{ 
    signed int tcodes[3][1]; 

    tcodes[0][0] = 0; 
    tcodes[0][1] = 1000; 
    tcodes[1][0] = 1000; 
    tcodes[1][1] = 0; 
    tcodes[2][0] = 0; 
    tcodes[2][1] = 1000; 
    tcodes[3][0] = 1000; 
    tcodes[3][1] = 0; 

    int x, y, c; 

    for(c = 0; c <= 3; c++) 
    { 
     printf("%d %d %d\r\n", c, tcodes[c][0], tcodes[c][1]); 

     x = 20; 
     y = 30; 
    } 

}

我期望這個程序來輸出:

0 0 1000 
1 1000 0 
2 0 1000 
3 1000 0 

但是,相反,我得到:

0 0 1000 
1 1000 0 
2 0 20 
3 20 30 

爲此,它會爲任何數量的分配爲x和y。出於某種原因,x和y在內存中覆蓋了數組的一部分。

有人可以解釋發生了什麼?

謝謝!

+0

它適合我。也許你的電腦有問題嗎? – 2010-04-30 01:05:14

+0

你使用什麼編譯器?我在使用gcc的gentoo 4.1.2 – scribbloid 2010-04-30 01:05:52

+2

這是未定義的行爲(http://en.wikipedia.org/wiki/Undefined_behavior)。它似乎在thyrgle的系統上工作,但它仍然是錯誤的。 – 2010-04-30 01:06:59

回答

5

其他的答案是正確的,但有助於解釋所發生的情況:

您有以下局部聲明:

signed int tcodes[3][1]; 
int x, y, c; 

那些獲取存儲緊挨着彼此的堆棧幀存儲器:

tcodes
X
ÿ
ž

tcodes有3個點,並試圖寫tcodes[n]只是意味着要尋找到tcodes點在內存中並移動到了第n點(我會忽略你的第二個維度,因爲它是無論如何只有1)。如果您嘗試寫入第3個點,它將從tcodes開始移動超過3個點,即使tcodes不是那麼大。由於x位於tcodes之後,因此在tcodes[3]處將會出現該內存被覆蓋並且值x發生變化。 tcodes[4]將覆蓋y,並且tcodes[5]將覆蓋z。如果您不斷增大n(或負值,這是合法的),您可以覆蓋您在內存中允許訪問的任何內容,這可能會以難以找到的方式搞砸您的程序

8

    tcodes[3][0] = 1000; 
    tcodes[3][1] = 0; 

正在寫出數組的末尾兩次。 [3]分配時隙ID 0-2,[1]只分配1個實際時隙[0]。

將您的tcode初始化更改爲signed int tcodes[4][2]; 4項兩項。

+4

而'[1]'只爲每一行分配插槽0。 – 2010-04-30 01:05:49

+0

是的,當我看到這一點時,打字速度儘可能快:) – 2010-04-30 01:07:16

5

它改成這樣:

signed int tcodes[4][2]; 
3

如果你像這樣定義一個數組:

int somearr[3]; 

你得到的是有3個元素的數組。索引開始形式0,所以,這些元素是:

somearr[0] 
somearr[1] 
somearr[2] 

數組和代碼中的函數中定義,像其他的變量,是在堆棧上分配。恰巧,變量x和y被放在堆棧旁邊的數組中。如果您嘗試訪問元素

tcodes[3][0] or tcodes[3][1] 

您訪問堆棧的一部分,這是你的陣列後面,作爲輸出顯示,它的點,其中變量x和y放置。

事實上這樣

signed int tcodes[3][1]; 

定義創建包含3個元素,其中的每一個是一個數組太陣列 - 包含一個符號的int陣列。當您編寫tcodes [1] [1]時,您正在訪問第二個數組中不存在的「第二個」元素。編譯器在解釋tcodes時[1] [1]與tcodes [2] [0]重疊的內存位置;

0

因爲您寫入超出數組邊界時,您正在寫入分配給堆棧上x和y變量的內存。在這種情況下,它們碰巧與tcodes [3] [0] == x和tcodes [3] [1] == y相同,因爲地址相同。 如果你在一個被調用的函數中執行它,並且該數組通過引用傳遞,那麼最終可能會導致堆棧損壞。底線是在C中,數組是基於0的。

0

您需要注意上述Robin Oster給出的解決方案。其他人可能會給你「太多的信息」。只需要更好地計算每個維度中的項目數量,請不要忘記第零個項目!