数组值自动更改为0

时间:2009-08-16 13:22:09

标签: c++ linux gcc

今天我遇到了与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不会在其他地方修改。

3 个答案:

答案 0 :(得分:8)

您需要向我们展示nod的定义。有一个很好的机会(基于你在1,而不是0开始数组的事实),你正在覆盖内存。

例如,如果将nod定义为:

int nod[3][2];

可能的数组下标是0-20-1不是 1-31-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]);

关于如何在内存中布置变量的实际细节可能与上述不同,但理论仍然有效。

如果结果是问题,可以采用两种可能的解决方案。

  • 使用零基数组作为C / C ++;或
  • 使用足够的空间定义它们以处理您的异常使用,例如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就会中断,它会告诉你新的和旧的值。