今天我遇到了与gcc的奇怪遭遇。请考虑以下代码:
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.........*/
唯一的区别是以粗体突出显示。问题是: 当稍后打印长度时,第一个代码打印len [1]和len [2](并在表达式中使用它们)为0.0000,而第二个代码打印并使用这些变量的正确值。
怎么了?我完全糊涂了。: -
注意:len不会在其他地方修改。
答案 0 :(得分:8)
您需要向我们展示nod
的定义。有一个很好的机会(基于你在1,而不是0开始数组的事实),你正在覆盖内存。
例如,如果将nod定义为:
int nod[3][2];
可能的数组下标是0-2
和0-1
,不是 1-3
和1-2
:
nod[0][0] nod[1][0] nod[2][0]
nod[0][1] nod[1][1] nod[2][1]
如果是的话,你的记忆几乎肯定会被覆盖,在这种情况下,所有的赌注都会被取消。你可能会破坏任何其他数据。
如果len
紧跟在nod
之后放在内存中,则此内存溢出将解释为什么它会被更改。下图将(尝试)说明这一点。假设您的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.2x10 -45 和5.6x10 -45 所以他们肯定打印时给出0.0000
(因为您似乎没有使用可以提供更精确值的格式字符串)。
测试此理论的一个好方法是在设置相关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]);
关于如何在内存中布置变量的实际细节可能与上述不同,但理论仍然有效。
如果结果是问题,可以采用两种可能的解决方案。
int nod[4][3]
。答案 1 :(得分:0)
你肯定有一个缓冲区覆盖。检查你的边界,你的示例中没有提供任何数组大小,这使我们无法说出更多。
如果您使用C ++,请尝试用std :: tr1 :: array或boost :: array替换您的数组(它们是相同的),这将为您提供一些线索。
答案 2 :(得分:0)
您可以尝试在gdb中设置watchpoint,以查看修改len
的时间。确保使用调试信息(-g
)和无优化(-O0
)编译程序。然后,在len
声明附近设置断点,添加watch len[0]
的观察点,然后运行。每当len[0]
被修改时,gdb就会中断,它会告诉你新的和旧的值。