我对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 :(得分: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给出的解决方案。其他人可能会给你“太多的信息”。只需更好地计算每个维度中的项目数量,不要忘记零项目计数!