为变量赋值会被存储在错误的位置吗?

时间:2010-04-30 01:00:41

标签: c arrays

我对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在内存中覆盖了数组的部分。

有人可以解释发生了什么吗?

谢谢!

6 个答案:

答案 0 :(得分:8)


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

两次写下数组的结尾。 [3]分配槽ID 0-2和[1]仅分配1个实际槽[0]。

将tcodes的初始化更改为signed int tcodes[4][2]; 4个条目2个条目。

答案 1 :(得分:5)

将其更改为:

signed int tcodes[4][2];

答案 2 :(得分:5)

其他答案是对的,但是为了帮助解释实际发生的事情:

您有以下本地声明:

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

那些在内存中的堆栈帧中彼此相邻存储:

  

tcodes
  X
  ÿ
  ž

tcodes有3个位置,尝试写入tcodes[n]只是意味着找到tcodes指向内存的位置并转移到n位置(I我会忽略你的第二个维度,因为它只是1。如果您尝试写入第3点,它将从tcodes的开头移动3​​个点,即使tcodes不是那么大。由于x位于tcodes之后,在tcodes[3]所在的位置,内存会被覆盖,x的值会发生变化。 tcodes[4]会覆盖y,而tcodes[5]会覆盖z。如果你继续使n更大(或者是负面的,这是合法的),你可以覆盖你在内存中允许访问的任何内容,这可能会以糟糕和难以找到的方式搞砸你的程序

答案 3 :(得分: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个元素的数组,每个元素也是一个数组 - 一个包含一个signed int的数组。当您编写tcodes [1] [1]时,您正在访问第二个数组中不存在的“second”元素。编译器在解释tcodes [1] [1]时访问的内存位置与tcodes [2] [0]重叠;

答案 4 :(得分:0)

当您在数组边界之外编写时,您正在写入分配给堆栈上的x和y变量的内存。在这种情况下,它们碰巧与tcodes [3] [0] == x和tcodes [3] [1] == y相同,因为地址相同。 如果您在被调用的函数中执行此操作并且数组通过引用传递,则可能最终导致堆栈损坏。 底线是在C中,数组基于0。

答案 5 :(得分:0)

你需要注意上面Robin Oster给出的解决方案。其他人可能会给你“太多的信息”。只需更好地计算每个维度中的项目数量,不要忘记零项目计数!